c++ 重写基类成员函数
目录
一、什么是函数重写?
二、用法与代码示例
三、为什么要重写函数?
实现多态性:
定制化行为:
接口实现:
四、函数重写的条件
五、注意事项
一、什么是函数重写?
在 C++ 中,函数重写是指在派生类(子类)中重新定义基类(父类)中声明为 virtual 的虚函数,以提供子类自己的实现。重写是实现**运行时多态性(Runtime Polymorphism)**的关键机制,允许通过基类指针或引用调用子类的具体实现。
简单来说:
-
基类定义了一个虚函数(用 virtual 关键字标记)。
-
子类对这个函数进行重新实现,替换基类的默认行为。
-
当通过基类指针或引用调用该函数时,实际执行的是子类的版本。
二、用法与代码示例
要实现函数重写,需要以下步骤:
-
在基类中将函数声明为 virtual。
-
在子类中重新定义该函数,函数签名必须与基类一致。
-
可选:在子类中使用 override 关键字(C++11 引入)明确表示重写。
示例 1:基本重写
#include <iostream>
using namespace std;
class Base {
public:
virtual void display() { // 声明为虚函数
cout << "Base class display" << endl;
}
};
class Derived : public Base {
public:
void display() override { // 重写基类的虚函数
cout << "Derived class display" << endl;
}
};
int main() {
Base* ptr = new Derived(); // 基类指针指向派生类对象
ptr->display(); // 调用的是 Derived 的版本
delete ptr;
return 0;
}
输出:
Derived class display
示例 2:多态性与多层继承
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() {
cout << "Some generic sound" << endl;
}
};
class Dog : public Animal {
public:
void speak() override {
cout << "Woof!" << endl;
}
};
class Puppy : public Dog {
public:
void speak() override {
cout << "Yip!" << endl;
}
};
int main() {
Animal* a1 = new Dog();
Animal* a2 = new Puppy();
a1->speak(); // 输出 "Woof!"
a2->speak(); // 输出 "Yip!"
delete a1;
delete a2;
return 0;
}
输出:
Woof!
Yip!
三、为什么要重写函数?
-
实现多态性:
-
重写是 C++ 中运行时多态的核心。通过基类指针或引用调用虚函数时,可以动态决定调用哪个类的实现。
-
这在需要处理一组相关但行为不同的对象时非常有用(如上面的 Animal 示例)。
-
-
定制化行为:
-
子类可能需要改变基类的默认行为以适应特定需求。例如,Dog 的 speak() 和 Puppy 的 speak() 有不同的表现。
-
-
接口实现:
-
如果基类是抽象类(包含纯虚函数 virtual void func() = 0;),子类必须重写这些函数以提供具体实现,否则无法实例化。
-
四、函数重写的条件
要正确重写基类的虚函数,必须满足以下条件:
-
基类函数是虚数: 必须用 virtual 关键字声明,否则子类的版本只是隐藏(Hide)而不是重写。
-
函数签名一致:
-
函数名、参数列表(数量和类型)、返回类型必须与基类一致。
-
例外:C++ 支持协变返回类型(Covariant Return Type),即返回类型可以是基类返回类型的派生类。
-
-
访问权限:子类的重写函数不能降低基类的访问权限(例如基类是 public,子类不能改为 private)。
五、注意事项
-
不要混淆函数重写与函数重载。成员函数的重写是指在派生类中提供函数新的定义。 函数重载是指用不同签名创建函数的多个版本。
-
在重写一个基类的重载成员函数时,基类成员函数的所有重载版本都会被覆盖掉,意味着访问其他版本的成员函数的唯一方式是显式的调用基类成员函数。因此,如果要重写重载成员函数,最好重写重载函数的每个版本。