26.禁止重写

26.面向对象-多态-禁止重写


26.1 知识点

知识回顾 强行禁止类被继承

  • 如果我们不希望一个类可以被继承

  • 我们可以通过 final 关键词来修饰类

  • 基本语法:

    class 类名 final
    {
    };
    
  • 在类名后加上 final 关键字,就可以禁止该类被继承了

禁止重写

  • final 关键字除了可以禁止类被继承

  • 还可以限制函数不能再被重写

  • 语法规则:

    • 在函数尾部加上 final
    • 它只能搭配 virtualoverride 使用
    • 因为它是用来禁止虚函数被重写的

示例代码如下:

#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 可以明确表达我们的设计意图:

  1. 这个函数我不允许别人改!
    给虚函数加 final,表示它不应该再被派生类重写。

  2. 这个类我不允许别人继承!
    给类加 final,表示它不能作为基类被继承。

主要的好处:

  1. 阻止子类误改重要逻辑,破坏设计
    比如某些算法的关键步骤,不希望被不小心重写。

  2. 在协同开发(多人开发)时,帮助其他人理解类的继承边界
    明确哪些类是可以扩展的,哪些类是封闭的。

  3. 在多人开发时,可以防止某些设计被越改越乱
    保持架构稳定和清晰。

总结:
final 是设计中“封闭继承/重写”的表达,是对封装性和架构安全的补充,有助于提高代码的可维护性。



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏