C++ final和override
1. final
关键字
a. 用途
final
关键字用于两个方面:
- 修饰类:防止类被继承。
- 修饰虚函数:防止虚函数被重写(覆盖)。
b. final
修饰类
当一个类被声明为 final
,它就不能被继承。也就是说,任何继承该类的尝试都会导致编译错误。
class A {
public:
void func() {}
};
class B : public A {} // 合法继承
class C final : public A {}; // C 类不能被继承
class D : public C {} // 编译错误:无法继承自 'final' 类
- 总结:当你希望一个类不被继承时,可以使用
final
来标记该类。
c. final
修饰虚函数
当 final
用于虚函数时,它表示该函数不能在子类中被重写(覆盖)。
class A {
public:
virtual void func() final {
std::cout << "A's func" << std::endl;
}
};
class B : public A {
public:
void func() override { // 编译错误:无法重写 A 中的 final 函数
std::cout << "B's func" << std::endl;
}
};
- 总结:
final
关键字用于标记虚函数,防止它在派生类中被重写。这样可以确保父类中的实现不可被更改。
2. override
关键字
a. 用途
override
用于标记子类中的虚函数,明确表示该函数是用来重写父类的虚函数的。这个关键字可以帮助编译器进行更多的检查,以确保子类中的函数确实覆盖了父类的虚函数。
b. 使用场景
当子类重写父类的虚函数时,使用 override
来明确标识。这不仅是为了可读性,还能帮助编译器检查是否真的有虚函数被重写。
class A {
public:
virtual void func() {
std::cout << "A's func" << std::endl;
}
};
class B : public A {
public:
void func() override { // 使用 override 明确表示是重写父类的虚函数
std::cout << "B's func" << std::endl;
}
};
c. 编译器检查
如果子类的函数没有正确重写父类的虚函数(例如,函数签名不同),编译器会给出错误提示。
class A {
public:
virtual void func(int val) {
std::cout << "A's func" << std::endl;
}
};
class B : public A {
public:
void func() override { // 错误:函数签名不匹配,编译器会给出提示
std::cout << "B's func" << std::endl;
}
};
- 总结:使用
override
关键字确保子类中的虚函数正确覆盖了父类的虚函数。如果签名不匹配或其它原因不能覆盖,编译器会报错。
3. final
和 override
配合使用
这两个关键字可以一起使用。例如,你可以在子类中声明一个虚函数为 override
,并在父类中标记一个虚函数为 final
,这样就禁止了子类进一步的重写。
class A {
public:
virtual void func() final { // 不能被重写
std::cout << "A's func" << std::endl;
}
};
class B : public A {
public:
void func() override { // 错误:父类函数是 final,不能重写
std::cout << "B's func" << std::endl;
}
};
总结
final
用来禁止继承或者禁止重写虚函数。用于类时防止继承,用于函数时防止重写。override
用来明确标识子类函数是重写父类的虚函数,它能帮助编译器检查函数是否正确覆盖了父类的虚函数。
如果你在编码时使用这两个关键字,不仅可以提升代码的安全性和清晰度,还能减少潜在的错误,确保继承和重写的正确性。