欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > C++ 多态

C++ 多态

2025/3/24 23:05:43 来源:https://blog.csdn.net/azaz_plus/article/details/146409024  浏览:    关键词:C++ 多态

一、多态的条件

1. ​定义

多态允许通过基类指针或引用,调用派生类对象的特定方法,实现“一个接口,多种实现”。

2. ​条件
  • 基类必须定义虚函数(virtual)​:虚函数是多态的核心机制。
  • 派生类必须重写(覆盖)基类的虚函数:派生类提供虚函数的具体实现(虚函数的重写要求继承父子关系的两个虚函数,函数,参数,返回值相同)。
  • 必须通过基类指针或引用调用虚函数:直接通过对象调用虚函数不触发多态(看的是基类指针指向的内容,如果是父类就调用父类的函数,子类就调用子类的函数)。
  • 注意:派生类重写可以不加virtual但是父类必须加 因为本质是重写了父类的实现,注意是重写了父类的实现,也就是说本质还是调用父类函数,但是内容变成了调用子类的函数内容
3. ​示例
class Animal {
public:virtual void speak() { cout << "Animal speaks" << endl; } // 虚函数
};class Dog : public Animal {
public:void speak() override { // 重写基类虚函数(C++98 无需写 override)cout << "Dog barks" << endl;}
};int main() {Animal* animal = new Dog();animal->speak(); // 输出 "Dog barks"(多态)delete animal;return 0;
}

二、重写与隐藏

1. ​重写(覆盖)​
  • 定义:派生类重新定义基类的虚函数,函数签名(函数名、参数列表、返回类型)必须一致(协变除外)。
  • 示例
    class Base {
    public:virtual void func(int x) { cout << "Base::func(int)" << endl; }
    };class Derived : public Base {
    public:void func(int x) { cout << "Derived::func(int)" << endl; } // 重写
    };
2. ​隐藏(重定义)​
  • 定义:派生类定义与基类同名的非虚函数(无论参数是否相同),将隐藏基类的同名函数。
  • 示例
    class Base {
    public:void func(int x) { cout << "Base::func(int)" << endl; }
    };class Derived : public Base {
    public:void func(double x) { cout << "Derived::func(double)" << endl; }
    };int main() {Derived d;d.func(1);    // 调用 Derived::func(double)(隐藏基类 func(int))d.Base::func(1); // 显式调用基类方法return 0;
    }

三、抽象类

1. ​定义
  • 抽象类包含至少一个 ​纯虚函数​,不能实例化。
  • 语法virtual 返回类型 函数名(参数) = 0;
  • 如果派生类继承了父类,而父类是一个抽象类则派生类也无法实例化,但是如果重写了纯虚函数的话,就能够实例化了,也就是说,纯虚函数间接的强制了派生类去重写这个虚函数
  • 实现继承:普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实 现。
  • 接口继承:虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成 多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数
2. ​示例
class Shape { // 抽象类
public:virtual double area() const = 0; // 纯虚函数
};class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() const override { // 必须实现纯虚函数return 3.14 * radius * radius;}
};int main() {// Shape s; // 错误:抽象类不能实例化Shape* shape = new Circle(5.0);cout << shape->area(); // 输出圆的面积delete shape;return 0;
}

四、虚函数表

1. ​虚函数表
  • 每个有虚函数的类都有一个虚函数表,表中存储该类的虚函数地址。
  • 虚函数表在编译时生成,每个类的虚函数表唯一。
2. ​虚表指针​
  • 每个对象内部包含一个指向虚函数表的指针,在对象构造时初始化。
  • 调用虚函数时,通过指针找到虚函数表,再通过偏移量调用具体函数。
  • 注意虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是他的指针又存到了虚表中。

五、override与final

1. override 关键字

作用:

  • 显式标记派生类中的虚函数是对基类虚函数的重写。
  • 修饰派生类的虚函数,检查是否完成重写,如果没完成重写就会报错。

  • 编译器检查:若函数签名与基类虚函数不一致(如参数、常量性不同),会报错,避免错误的重写。

示例:

class Base {
public:virtual void print() const {std::cout << "Base" << std::endl;}
};class Derived : public Base {
public:// 正确:签名一致,重写基类虚函数void print() const override {std::cout << "Derived" << std::endl;}
};class IncorrectDerived : public Base {
public:// 错误:参数不一致,override 触发编译错误void print(int) const override {std::cout << "IncorrectDerived" << std::endl;}
};

2. final 关键字

作用:

  • 修饰类:禁止类被继承。
  • 修饰虚函数:禁止派生类进一步重写该函数。
  • 可同时与 override 使用(顺序无关,如 override final)。
  • 修饰类时,放在类名后(class Base final {};)。
  • 修饰函数时,放在函数参数列表后(void foo() final {})。

示例:

修饰类:​

class Base final {}; // Base 不能被继承// 错误:尝试继承 final 类
class Derived : public Base {};

修饰虚函数:​

class Base {
public:virtual void foo() final {} // 基类虚函数标记为 final
};class Derived : public Base {
public:// 错误:无法重写 final 函数void foo() override {}
};

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词