Skip to content

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 引入的,它的主要作用是:

  1. 明确意图:明确告诉编译器,这个函数是重写父类的方法
  2. 编译检查:如果函数没有正确重写父类的方法,编译器会报错
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 关键字可以用于:

  1. 防止类被继承:将类声明为 final,表示该类不能被继承
  2. 防止方法被重写:将方法声明为 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. 重写的条件

要成功重写父类的方法,必须满足以下条件:

  1. 相同的方法签名:方法的名称、参数列表和返回类型必须完全相同
  2. 虚函数:父类的方法必须是 virtual 函数
  3. 继承关系:子类必须继承自父类
  4. 访问权限:子类方法的访问权限不能比父类更严格(可以更宽松)
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 关键字?

  1. 当我们确定一个类不需要被继承时
  2. 当我们确定一个方法不需要被重写时
  3. 为了安全起见,防止继承导致的错误

问题 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. 最佳实践

  1. 使用 override:在重写父类方法时,始终使用 override 关键字
  2. 设计清晰的继承层次:避免过度继承,保持层次简单
  3. 考虑使用 final:在适当的情况下使用 final 关键字,提高代码安全性
  4. 确保虚函数正确实现:确保每个虚函数都有正确的实现,避免未定义行为

总结

函数重写是 C++ 继承和多态的核心概念之一。通过重写,子类可以根据自身特点重新实现父类的方法。override 关键字可以提高代码的可读性和安全性,final 关键字可以防止不必要的继承和重写。


练习建议: 1. 设计一个图形类层次结构,包含形状、矩形、圆形等 2. 实现虚函数和重写 3. 使用 override 关键字明确重写意图 4. 测试多态行为