C++ OOP 面试高频知识点 - 07
函数重写 override,final 关键字
1. 函数重写的基本概念
函数重写(Override) 是在继承关系中,子类重新实现父类中已经存在的方法,方法的签名(名称、参数列表、返回类型)必须完全相同。函数重写是实现多态的重要方式。
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Dog barks" << endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Cat meows" << endl;
}
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->makeSound(); // 调用 Dog::makeSound()
animal2->makeSound(); // 调用 Cat::makeSound()
delete animal1;
delete animal2;
return 0;
}
2. override 关键字
override 关键字是 C++11 引入的,它的主要作用是:
- 明确意图:明确告诉编译器,这个函数是重写父类的方法
- 编译检查:如果函数没有正确重写父类的方法,编译器会报错
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public:
// 正确的重写
void makeSound() override {
cout << "Dog barks" << endl;
}
// 错误:参数列表不同,不是重写
void makeSound(int volume) override { // 编译错误
cout << "Dog barks loudly" << endl;
}
};
3. final 关键字
final 关键字可以用于:
- 防止类被继承:将类声明为
final,表示该类不能被继承 - 防止方法被重写:将方法声明为
final,表示该方法不能在子类中被重写
3.1 防止类被继承
class Animal final {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal { // 编译错误:Animal 是 final 类
public:
void makeSound() override {
cout << "Dog barks" << endl;
}
};
3.2 防止方法被重写
class Animal {
public:
virtual void makeSound() final {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override { // 编译错误:makeSound 是 final 方法
cout << "Dog barks" << endl;
}
};
4. 重写的条件
要成功重写父类的方法,必须满足以下条件:
- 相同的方法签名:方法的名称、参数列表和返回类型必须完全相同
- 虚函数:父类的方法必须是
virtual函数 - 继承关系:子类必须继承自父类
- 访问权限:子类方法的访问权限不能比父类更严格(可以更宽松)
class Animal {
protected:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public: // 访问权限更宽松,是允许的
void makeSound() override {
cout << "Dog barks" << endl;
}
};
class Cat : public Animal {
private: // 访问权限更严格,不允许
void makeSound() override { // 编译错误
cout << "Cat meows" << endl;
}
};
5. 常见问题和回答
问题 1:重写和重载的区别?
- 重写(Override):在继承关系中,子类重新实现父类的方法,方法签名完全相同
- 重载(Overload):在同一个作用域内,函数名称相同但参数列表不同
问题 2:为什么需要 override 关键字?
使用 override 关键字可以明确重写意图,并防止因方法签名不匹配导致的错误。
class Animal {
public:
virtual void makeSound() = 0;
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Dog barks" << endl;
}
};
问题 3:什么时候使用 final 关键字?
- 当我们确定一个类不需要被继承时
- 当我们确定一个方法不需要被重写时
- 为了安全起见,防止继承导致的错误
问题 4:重写可以改变方法的返回类型吗?
在 C++ 中,重写的方法可以返回协变类型(Covariant Types),即子类方法的返回类型可以是父类方法返回类型的子类。
class Base {
public:
virtual Base* clone() const {
return new Base(*this);
}
};
class Derived : public Base {
public:
Derived* clone() const override { // 协变返回类型
return new Derived(*this);
}
};
6. 最佳实践
- 使用 override:在重写父类方法时,始终使用
override关键字 - 设计清晰的继承层次:避免过度继承,保持层次简单
- 考虑使用 final:在适当的情况下使用
final关键字,提高代码安全性 - 确保虚函数正确实现:确保每个虚函数都有正确的实现,避免未定义行为
总结
函数重写是 C++ 继承和多态的核心概念之一。通过重写,子类可以根据自身特点重新实现父类的方法。override 关键字可以提高代码的可读性和安全性,final 关键字可以防止不必要的继承和重写。
练习建议: 1. 设计一个图形类层次结构,包含形状、矩形、圆形等 2. 实现虚函数和重写 3. 使用 override 关键字明确重写意图 4. 测试多态行为