掘金 后端 ( ) • 2024-03-23 09:41

C++11标准引入的 finaloverride 这两个关键字,标志着 C++ 对面向对象编程特性的进一步增强。

这两个关键字的设计初衷,主要是为了提高代码的清晰度、安全性以及维护性。

接下来,我将分别介绍这两个关键字的背景和用法,并通过代码示例加以说明。

final 关键字

在 C++11 之前,C++没有直接的语法支持来阻止一个类被继承或一个虚函数被子类重写。

这意味着,无论你的设计意图如何,使用你的类的其他开发者,总是可以通过继承你的类,并重写其虚函数的方式来扩展你的类。

这在很多情况下是有用的,但在某些设计场景下,你可能希望禁止这种行为,以保证类的设计和安全性不被破坏。

final 关键字的引入,给C++程序员提供了更多的控制权,允许他们精确地指定类和虚函数的继承属性。

使用 final,开发者可以明确指出哪些类不应该被继承,哪些虚函数不应该被进一步覆盖。这样不仅能够帮助维护类的设计意图,还能避免潜在的错误和性能损失。

final 的用法

1、防止类被继承

final关键字放在类名后面时,这个类就不能被继承了。

class Base final { // Base类不能被继承
public:
    virtual void doSomething() {
        // 实现...
    }
};

// 下面的代码会导致编译错误
class Derived : public Base { // 错误:Base是final的
public:
    void doSomething() override {
        // 尝试覆盖
    }
};

2、防止虚函数被覆盖

final关键字放在虚函数声明的末尾时,这个虚函数在任何派生类中都不能被覆盖。

class Base {
public:
    virtual void doSomething() final { // doSomething不能在派生类中被覆盖
        // 实现...
    }
};

class Derived : public Base {
public:
    void doSomething() override { // 错误:doSomething是final的
        // 尝试覆盖
    }
};

override 关键字

在 C++11 之前,没有一个直接的方法来确保派生类的函数确实重写了基类中的虚函数。

如果派生类中声明的函数,由于签名不匹配(例如,参数类型或数量不同)而没有覆盖基类中的函数,编译器将不会发出警告或错误。这种情况下的函数将被视为派生类的一个新函数,而不是重写的函数。这可能导致程序的行为不符合预期,且错误可能难以检测。

override 关键字的引入,提供了一种机制,来确保派生类中的函数,确实覆盖了基类中的某个虚函数。如果标记为override的函数没有从任何基类中重写虚函数,编译器将报错。

这样做不仅增加了代码的清晰度,使得开发者一目了然地知道某个函数是用来重写基类中的虚函数,而且还大大增强了类型安全,避免了潜在的错误。

override 的用法

1、基本用法示例

下面的代码展示了如何使用override关键字来确保派生类的方法,确实重写了基类中的虚方法。

class Base {
public:
    virtual void someFunction(int) {
        // 基类中的虚函数实现
    }
};

class Derived : public Base {
public:
    void someFunction(int) override {
        // 确实重写了基类中的虚函数
    }
};

在上述代码中,Derived 类中的 someFunction 函数通过override关键字,明确表示它是重写基类 Base 中的虚函数。

如果我们在Derived类中错误地声明了 someFunction 函数(比如参数类型不匹配),编译器会立即报错,指出这里没有任何函数被重写。

2、错误用法示例

下面的代码展示一个常见的错误场景,如果没有使用override关键字,这种错误可能不会被及时发现。

class Base {
public:
    virtual void someFunction(int) {
        // 基类中的虚函数实现
    }
};

class Derived : public Base {
public:
    void someFunction(double) override { // 错误:没有匹配的基类虚函数
        // 意图是重写基类中的函数,但是参数类型不匹配
    }
};

这个例子中,Derived 类试图通过s omeFunction(double) 重写基类中的 someFunction(int) 函数,但是由于参数类型不匹配,这里没有重写任何基类中的虚函数。因为我们使用了override关键字,编译器将报错,指出我们的重写尝试失败了。

总结

finaloverride这两个关键字的引入,使得C++ 在面向对象编程方面的能力更加完善。

通过使用final,类的设计者可以控制类的继承关系和虚函数的重写行为,而override则强化了派生类对基类虚函数重写的准确性,避免了因签名不匹配而导致的错误。

这两个关键字的使用,提高了C++程序的安全性、清晰度和维护性。