26.面向对象-多态-禁止重写
26.1 知识点
知识回顾 强行禁止类被继承
如果我们不希望一个类可以被继承
我们可以通过
final
关键词来修饰类基本语法:
class 类名 final { };
在类名后加上
final
关键字,就可以禁止该类被继承了
禁止重写
final
关键字除了可以禁止类被继承还可以限制函数不能再被重写
语法规则:
- 在函数尾部加上
final
- 它只能搭配
virtual
和override
使用 - 因为它是用来禁止虚函数被重写的
- 在函数尾部加上
示例代码如下:
#pragma once
#include <iostream>
using namespace std;
class Grandpa
{
public:
// 如果在虚函数后面直接加上final
// 意义是
// 1. 让子类无法重写
// 2. 让子类也无法去写一个同名函数
virtual void Test();
};
#include "Grandpa.h"
void Grandpa::Test()
{
cout << "GrandPa" << endl;
}
#pragma once
#include "Grandpa.h"
class Father :
public Grandpa
{
public:
void Test() override final; // 子类不能再重写这个函数了
};
#include "Father.h"
void Father::Test()
{
cout << "Father" << endl;
}
#pragma once
#include "Father.h"
class Son :
public Father
{
public:
// void Test() override; // 报错 不可重写
};
#include "Son.h"
// 报错不可重写
// void Son::Test()
// {
// cout << "Son" << endl;
// }
调用示例:
Grandpa* s = new Son();
s->Test(); // Father 调用的是最后一个被重写的函数
26.2 知识点代码
Grandpa.h
#pragma once
#include <iostream>
using namespace std;
class Grandpa
{
public:
//如果在虚函数后面直接加上final
//意义是
//1.让子类无法重写
//2.让子类也无法去写一个同名函数
virtual void Test();
};
Grandpa.cpp
#include "Grandpa.h"
void Grandpa::Test()
{
cout << "GrandPa" << endl;
}
Father.h
#pragma once
#include "Grandpa.h"
class Father :
public Grandpa
{
public:
void Test() override final;//子类不能再重写这个函数了
};
Father.cpp
#include "Father.h"
void Father::Test()
{
cout << "Father" << endl;
}
Son.h
#pragma once
#include "Father.h"
class Son :
public Father
{
public:
//void Test() override;//报错 不可重写
};
Son.cpp
#include "Son.h"
//报错不可重写
//void Son::Test()
//{
// cout << "Son" << endl;
//}
Lesson26_面向对象_多态_禁止重写.cpp
#include <iostream>
#include "Son.h"
int main()
{
#pragma region 知识回顾 强行禁止类被继承
//如果我们不希望一个类可以被继承
//我们可以通过final关键词来修饰类
//基本语法:
//class 类名 final
//{
//}
//在类名后加上final关键字,就可以禁止该类被继承了
#pragma endregion
#pragma region 知识点 禁止重写
//final关键字除了可以禁止类被继承
//还可以限制函数不能再被重写
//语法规则:
//在函数尾部加上 final
//它只能搭配 virtual和override使用
//因为它是用来禁止虚函数被重写的
Grandpa* s = new Son();
s->Test();//Father 调用的是最后一个被重写的函数
#pragma endregion
}
26.3 练习题
下列哪种情况下 final 关键字使用是合法的?
选项解析:
A. 用在非虚函数上以禁止重写
❌ 错误。final
只能用于虚函数(virtual
)上,用于表示该函数不能再被子类重写。非虚函数本身就不能被重写,加 final
没有意义且不合法。
B. 用在类上以禁止被继承
✅ 正确。final
用在类声明后,可以阻止该类被进一步继承,表示这个类是“最终类”。
C. 用在普通成员变量上以禁止修改
❌ 错误。C++ 中没有办法用 final
来修饰变量来表示不可变。要禁止修改变量,一般用 const
,而不是 final
。
D. 用在构造函数上以禁止继承
❌ 错误。构造函数本身不能被继承,用 final
修饰构造函数是不合法的。
正确答案:B
若基类函数 virtual void foo() final;
,以下哪一项在派生类中是合法的?
基类中声明如下:
class Base {
public:
virtual void foo() final;
};
意味着 foo()
在派生类中不能被重写,任何对 foo()
的重写都会导致编译错误。
选项解析:
A. void foo();
❌ 错误。虽然没有加 override
,但这仍然是对基类 foo()
的重写,违反了 final
的规则。
B. virtual void foo();
❌ 错误。同样是试图重写 foo()
,非法。
C. void foo() override;
❌ 错误。显式声明为重写,等同于 A,仍然不合法。
D. virtual void foo(int i);
✅ 正确。这个函数与基类中的 foo()
签名不同,属于重载而不是重写,因此合法。
正确答案:D
final 只能用于虚函数或类上,不能单独用于普通成员函数。
✅ 正确。
解析:final
是 C++11 引入的,用于:
- 修饰虚函数:禁止该虚函数在派生类中被重写;
- 修饰类:禁止该类被继承。
不能用于:
- 普通函数(非虚函数);
- 构造函数;
- 成员变量。
正确答案:正确
你认为 final 对我们来说有什么作用?
参考答案:
加上 final
可以明确表达我们的设计意图:
这个函数我不允许别人改!
给虚函数加final
,表示它不应该再被派生类重写。这个类我不允许别人继承!
给类加final
,表示它不能作为基类被继承。
主要的好处:
阻止子类误改重要逻辑,破坏设计
比如某些算法的关键步骤,不希望被不小心重写。在协同开发(多人开发)时,帮助其他人理解类的继承边界
明确哪些类是可以扩展的,哪些类是封闭的。在多人开发时,可以防止某些设计被越改越乱
保持架构稳定和清晰。
总结:final
是设计中“封闭继承/重写”的表达,是对封装性和架构安全的补充,有助于提高代码的可维护性。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com