1. 继承

继承允许我们根据一个已有的类来定义一个新的类。已有的类称为基类,新定义的类称为派生类派生类继承了基类的特性和行为,并且可以添加自己新的特性和行为,或者修改继承而来的行为。

主要目的: 实现代码复用和建立类之间的层次关系(是一种“is-a”的关系)。

继承的基本语法:

cpp

class 派生类名 : 访问说明符 基类名 {
    // ... 派生类的新成员 ...
};

访问说明符可以是 publicprotected, 或 private。最常用的是 public 继承。

示例:
#include <iostream>
#include <string>
using namespace std;

// 基类
class Animal {
public:
    string name;
    void eat() {
        cout << name << " is eating." << endl;
    }
};

// 派生类 Dog 公有继承 Animal
class Dog : public Animal {
public:
    void bark() {
        cout << name << " says: Woof!" << endl; // name 是从 Animal 继承来的
    }
};

// 派生类 Cat 公有继承 Animal
class Cat : public Animal {
public:
    void meow() {
        cout << name << " says: Meow!" << endl;
    }
};

int main() {
    Dog myDog;
    myDog.name = "Buddy"; // 继承自 Animal 的成员
    myDog.eat();          // 继承自 Animal 的方法
    myDog.bark();         // 自己的方法

    Cat myCat;
    myCat.name = "Whiskers";
    myCat.eat();
    myCat.meow();

    return 0;
}

输出:

Buddy is eating.
Buddy says: Woof!
Whiskers is eating.
Whiskers says: Meow!

在这个例子中:

  • Dog 和 Cat 都是 Animal

  • 它们自动获得了 Animal 的 name 属性和 eat() 方法。

  • 它们还添加了自己特有的方法 bark() 和 meow()


2. 多态

多态的字面意思是“多种形态”。在C++中,它指的是当使用基类的指针或引用来调用一个虚函数时,程序会根据指针或引用所指向的实际对象的类型来决定调用哪个类的函数

主要目的: 实现接口的统一,让不同派生类的对象对同一消息做出不同的响应。

多态的实现依赖于两个关键技术:

  1. 虚函数: 在基类中使用 virtual 关键字声明的函数。

  2. 动态绑定: 函数调用在程序运行时(而不是编译时)才被解析。

多态的基本语法和示例:
#include <iostream>
#include <string>
using namespace std;

// 基类
class Animal {
public:
    string name;
    // 关键:声明虚函数
    virtual void speak() {
        cout << name << " makes a sound." << endl;
    }
    // 虚析构函数(非常重要!)
    virtual ~Animal() {} 
};

class Dog : public Animal {
public:
    // 重写基类的虚函数(override关键字是C++11引入的,确保正确重写)
    void speak() override {
        cout << name << " says: Woof!" << endl;
    }
};

class Cat : public Animal {
public:
    void speak() override {
        cout << name << " says: Meow!" << endl;
    }
};

// 一个通用的函数,接收基类的指针
void animalSays(Animal* animal) {
    animal->speak(); // 关键:这里调用哪个 speak() 取决于传入的实际对象
}

int main() {
    Dog myDog;
    myDog.name = "Buddy";

    Cat myCat;
    myCat.name = "Whiskers";

    // 多态的魔力所在
    animalSays(&myDog); // 输出: Buddy says: Woof!
    animalSays(&myCat); // 输出: Whiskers says: Meow!

    // 另一种常见用法:基类指针数组
    Animal* animals[2] = {&myDog, &myCat};
    for (int i = 0; i < 2; ++i) {
        animals[i]->speak();
    }
    // 输出:
    // Buddy says: Woof!
    // Whiskers says: Meow!

    return 0;
}
多态的工作原理(简化的虚函数表):
  1. 当一个类包含虚函数时,编译器会为该类创建一个 虚函数表

  2. 这个表就像一个数组,里面存放着该类所有虚函数的地址。

  3. 每个该类的对象都会包含一个隐藏的指针(vptr),指向这个虚函数表。

  4. 当通过基类指针调用虚函数时,程序会通过对象的 vptr 找到对应的虚函数表,然后从表中查找并调用正确的函数版本。

重要注意事项:
  • 虚析构函数: 如果一个类可能被继承,并且可能会通过基类指针来删除派生类对象,那么基类的析构函数必须是虚函数。否则,只会调用基类的析构函数,而不会调用派生类的析构函数,导致资源泄漏。

更多推荐