C++ Primer Plus 第13章:类继承

13.1 继承的基本概念

13.1.1 为什么需要继承?

继承允许从已有类(基类)派生出新类(派生类),派生类自动拥有基类的属性和方法,并可以添加新功能或修改已有功能。

复制代码
继承关系示意:
        ┌─────────────────┐
        │   Animal(基类) │
        │  - name         │
        │  - age          │
        │  + eat()        │
        │  + sleep()      │
        └────────┬────────┘
                 │ 继承
        ┌────────┴────────┐
        │                 │
┌───────┴──────┐  ┌───────┴──────┐
│  Dog(派生类)│  │  Cat(派生类)│
│  + bark()    │  │  + meow()    │
│  + fetch()   │  │  + purr()    │
└──────────────┘  └──────────────┘

派生类拥有:基类的所有成员 + 自己新增的成员

继承的好处:

  • 代码复用:不重复编写相同的代码
  • 扩展性:在已有功能基础上添加新功能
  • 多态性:统一接口,不同实现

13.1.2 基本继承语法

cpp 复制代码
// 语法格式:
class 派生类名 : 访问说明符 基类名
{
    // 派生类新增的成员
};

// 访问说明符:public(最常用)、protected、private

13.2 公有继承(public inheritance)

13.2.1 基类与派生类的基本示例

cpp 复制代码
// inheritance_basic.cpp -- 公有继承基础
#include <iostream>
#include <string>

// ===== 基类 =====
class TableTennisPlayer
{
private:
    std::string firstname;
    std::string lastname;
    bool        hasTable;

public:
    TableTennisPlayer(const std::string& fn = "none",
                      const std::string& ln = "none",
                      bool ht = false)
        : firstname(fn), lastname(ln), hasTable(ht)
    {
        std::cout << "[基类构造] " << fn << " " << ln << std::endl;
    }

    ~TableTennisPlayer()
    {
        std::cout << "[基类析构] " << firstname << std::endl;
    }

    void name() const
    {
        std::cout << lastname << ", " << firstname << std::endl;
    }

    bool hasATable() const { return hasTable; }

    void resetTable(bool v) { hasTable = v; }
};

// ===== 派生类 =====
class RatedPlayer : public TableTennisPlayer
{
private:
    unsigned int rating;   // 派生类新增的成员

public:
    // 派生类构造函数:必须调用基类构造函数
    RatedPlayer(unsigned int r,
                const std::string& fn,
                const std::string& ln,
                bool ht = false)
        : TableTennisPlayer(fn, ln, ht),   // 调用基类构造函数
          rating(r)
    {
        std::cout << "[派生类构造] rating=" << r << std::endl;
    }

    // 也可以用基类对象初始化
    RatedPlayer(unsigned int r, const TableTennisPlayer& tp)
        : TableTennisPlayer(tp),   // 调用基类拷贝构造
          rating(r)
    {
        std::cout << "[派生类构造2] rating=" << r << std::endl;
    }

    ~RatedPlayer()
    {
        std::cout << "[派生类析构] rating=" << rating << std::endl;
    }

    unsigned int getRating() const { return rating; }
    void setRating(unsigned int r) { rating = r; }
};

int main()
{
    using namespace std;

    cout << "===== 创建基类对象 =====" << endl;
    TableTennisPlayer player1("张", "三", true);
    player1.name();
    cout << "有球桌:" << boolalpha << player1.hasATable() << endl;

    cout << "\n===== 创建派生类对象 =====" << endl;
    RatedPlayer rplayer1(1140, "李", "四", true);
    rplayer1.name();          // 继承自基类
    rplayer1.hasATable();     // 继承自基类
    cout << "评级:" << rplayer1.getRating() << endl;  // 派生类新增

    cout << "\n===== 用基类对象初始化派生类 =====" << endl;
    RatedPlayer rplayer2(1212, player1);
    rplayer2.name();
    cout << "评级:" << rplayer2.getRating() << endl;

    cout << "\n===== 派生类赋值给基类(向上转型)=====" << endl;
    TableTennisPlayer& ref = rplayer1;   // 基类引用指向派生类对象
    ref.name();   // 调用基类方法

    cout << "\n===== 程序结束 =====" << endl;
    return 0;
}

输出(构造/析构顺序):

复制代码
===== 创建派生类对象 =====
[基类构造] 李 四        ← 先构造基类部分
[派生类构造] rating=1140 ← 再构造派生类部分

===== 程序结束 =====
[派生类析构] rating=1140 ← 先析构派生类部分
[基类析构] 李            ← 再析构基类部分

💡 构造/析构顺序

  • 构造:先基类,后派生类
  • 析构:先派生类,后基类(与构造相反)

13.3 派生类与基类的关系

13.3.1 访问控制在继承中的体现

cpp 复制代码
// access_in_inheritance.cpp -- 继承中的访问控制
#include <iostream>

class Base
{
public:
    int pub;        // 公有:任何地方可访问
protected:
    int prot;       // 保护:类内和派生类可访问
private:
    int priv;       // 私有:只有类内可访问

public:
    Base(int a, int b, int c) : pub(a), prot(b), priv(c) {}

    void showBase() const
    {
        std::cout << "pub=" << pub
                  << " prot=" << prot
                  << " priv=" << priv << std::endl;
    }
};

class Derived : public Base
{
public:
    int own;

    Derived(int a, int b, int c, int d)
        : Base(a, b, c), own(d) {}

    void showDerived() const
    {
        std::cout << "pub=" << pub    << std::endl;   // ✅ 可访问
        std::cout << "prot=" << prot  << std::endl;   // ✅ 可访问
        // std::cout << priv;                         // ❌ 不可访问
        std::cout << "own=" << own    << std::endl;   // ✅ 自己的成员
    }
};

int main()
{
    Derived d(1, 2, 3, 4);

    d.pub = 10;     // ✅ public成员,外部可访问
    // d.prot = 20; // ❌ protected成员,外部不可访问
    // d.priv = 30; // ❌ private成员,外部不可访问

    d.showBase();
    d.showDerived();

    return 0;
}

三种继承方式对比:

基类成员 public继承 protected继承 private继承
public public protected private
protected protected protected private
private 不可访问 不可访问 不可访问

13.3.2 派生类不能继承的内容

cpp 复制代码
// 派生类不能继承:
// 1. 构造函数(但可以调用)
// 2. 析构函数(但会自动调用)
// 3. 赋值运算符(但可以调用)
// 4. 友元函数(友元关系不继承)

13.4 虚函数与多态

13.4.1 为什么需要虚函数?

cpp 复制代码
// without_virtual.cpp -- 没有虚函数的问题
#include <iostream>

class Animal
{
public:
    void speak() const   // 非虚函数
    {
        std::cout << "动物发出声音" << std::endl;
    }
};

class Dog : public Animal
{
public:
    void speak() const   // 隐藏基类函数
    {
        std::cout << "汪汪汪!" << std::endl;
    }
};

class Cat : public Animal
{
public:
    void speak() const
    {
        std::cout << "喵喵喵!" << std::endl;
    }
};

int main()
{
    Dog dog;
    Cat cat;

    dog.speak();   // 汪汪汪!(正确)
    cat.speak();   // 喵喵喵!(正确)

    // 问题:通过基类指针调用时,无法实现多态!
    Animal* p1 = &dog;
    Animal* p2 = &cat;
    p1->speak();   // 动物发出声音(错误!应该是汪汪汪)
    p2->speak();   // 动物发出声音(错误!应该是喵喵喵)

    return 0;
}

13.4.2 虚函数实现多态

cpp 复制代码
// virtual_demo.cpp -- 虚函数实现多态
#include <iostream>
#include <string>

class Animal
{
protected:
    std::string name;

public:
    Animal(const std::string& n) : name(n) {}

    // virtual 关键字:声明虚函数
    virtual void speak() const
    {
        std::cout << name << " 发出声音" << std::endl;
    }

    virtual std::string getType() const
    {
        return "动物";
    }

    // 虚析构函数(含虚函数的类必须有!)
    virtual ~Animal()
    {
        std::cout << "[析构] " << name << std::endl;
    }

    void showInfo() const
    {
        std::cout << "类型:" << getType()
                  << " 名字:" << name << std::endl;
    }
};

class Dog : public Animal
{
public:
    Dog(const std::string& n) : Animal(n) {}

    // override 关键字(C++11):明确表示重写虚函数
    void speak() const override
    {
        std::cout << name << " 说:汪汪汪!" << std::endl;
    }

    std::string getType() const override
    {
        return "狗";
    }
};

class Cat : public Animal
{
public:
    Cat(const std::string& n) : Animal(n) {}

    void speak() const override
    {
        std::cout << name << " 说:喵喵喵!" << std::endl;
    }

    std::string getType() const override
    {
        return "猫";
    }
};

class Duck : public Animal
{
public:
    Duck(const std::string& n) : Animal(n) {}

    void speak() const override
    {
        std::cout << name << " 说:嘎嘎嘎!" << std::endl;
    }

    std::string getType() const override { return "鸭子"; }
};

// 多态函数:接受基类指针,调用正确的派生类方法
void makeSpeak(const Animal* animal)
{
    animal->speak();   // 根据实际类型调用正确的speak()
}

int main()
{
    using namespace std;

    Dog  dog("旺财");
    Cat  cat("咪咪");
    Duck duck("唐老鸭");

    cout << "===== 直接调用 =====" << endl;
    dog.speak();
    cat.speak();
    duck.speak();

    cout << "\n===== 通过基类指针(多态)=====" << endl;
    Animal* animals[] = {&dog, &cat, &duck};
    for (int i = 0; i < 3; i++)
    {
        animals[i]->showInfo();   // 调用虚函数getType()
        animals[i]->speak();      // 多态调用
    }

    cout << "\n===== 通过函数参数(多态)=====" << endl;
    makeSpeak(&dog);
    makeSpeak(&cat);
    makeSpeak(&duck);

    cout << "\n===== 动态分配(多态)=====" << endl;
    Animal* p = new Dog("小黑");
    p->speak();   // 汪汪汪!(虚函数正确调用)
    delete p;     // 调用Dog的析构函数(因为虚析构函数)

    return 0;
}

输出:

复制代码
===== 通过基类指针(多态)=====
类型:狗 名字:旺财
旺财 说:汪汪汪!
类型:猫 名字:咪咪
咪咪 说:喵喵喵!
类型:鸭子 名字:唐老鸭
唐老鸭 说:嘎嘎嘎!

13.4.3 虚函数的工作原理(虚函数表)

复制代码
虚函数表(vtable)机制:

Animal对象:
┌──────────────┐
│ vptr ────────┼──→ Animal的vtable
│ name         │    ┌─────────────────┐
└──────────────┘    │ speak → Animal::speak  │
                    │ getType → Animal::getType│
                    └─────────────────┘

Dog对象:
┌──────────────┐
│ vptr ────────┼──→ Dog的vtable
│ name         │    ┌─────────────────┐
└──────────────┘    │ speak → Dog::speak    │
                    │ getType → Dog::getType │
                    └─────────────────┘

通过基类指针调用虚函数时:
1. 找到对象的vptr
2. 通过vptr找到vtable
3. 在vtable中找到正确的函数地址
4. 调用该函数
→ 这就是运行时多态!

13.5 纯虚函数与抽象类

13.5.1 纯虚函数

cpp 复制代码
// abstract_class.cpp -- 纯虚函数与抽象类
#include <iostream>
#include <string>
#include <vector>
#include <cmath>

// 抽象类:含有纯虚函数的类
class Shape
{
protected:
    std::string color;

public:
    Shape(const std::string& c = "黑色") : color(c) {}

    // 纯虚函数:= 0,派生类必须实现
    virtual double area()      const = 0;
    virtual double perimeter() const = 0;
    virtual std::string name() const = 0;

    // 普通虚函数:有默认实现,派生类可以重写
    virtual void show() const
    {
        std::cout << name() << "(" << color << ")"
                  << " 面积=" << area()
                  << " 周长=" << perimeter() << std::endl;
    }

    virtual ~Shape() {}
};

// 不能实例化抽象类:
// Shape s;   // ❌ 错误!

class Circle : public Shape
{
private:
    double radius;
    static constexpr double PI = 3.14159265358979;

public:
    Circle(double r, const std::string& c = "红色")
        : Shape(c), radius(r) {}

    double area()      const override { return PI * radius * radius; }
    double perimeter() const override { return 2 * PI * radius; }
    std::string name() const override { return "圆形"; }
};

class Rectangle : public Shape
{
private:
    double width, height;

public:
    Rectangle(double w, double h, const std::string& c = "蓝色")
        : Shape(c), width(w), height(h) {}

    double area()      const override { return width * height; }
    double perimeter() const override { return 2 * (width + height); }
    std::string name() const override { return "矩形"; }
};

class Triangle : public Shape
{
private:
    double a, b, c;   // 三边长

public:
    Triangle(double a, double b, double c,
             const std::string& col = "绿色")
        : Shape(col), a(a), b(b), c(c) {}

    double area() const override
    {
        double s = (a + b + c) / 2;
        return sqrt(s * (s-a) * (s-b) * (s-c));   // 海伦公式
    }
    double perimeter() const override { return a + b + c; }
    std::string name() const override { return "三角形"; }
};

int main()
{
    using namespace std;

    // 用基类指针管理不同形状(多态)
    vector<Shape*> shapes;
    shapes.push_back(new Circle(5.0));
    shapes.push_back(new Rectangle(4.0, 6.0));
    shapes.push_back(new Triangle(3.0, 4.0, 5.0));
    shapes.push_back(new Circle(3.0, "黄色"));

    cout << "===== 所有形状 =====" << endl;
    double totalArea = 0;
    for (const auto& s : shapes)
    {
        s->show();
        totalArea += s->area();
    }
    cout << "\n总面积:" << totalArea << endl;

    // 释放内存
    for (auto& s : shapes)
        delete s;

    return 0;
}

13.6 虚析构函数

cpp 复制代码
// virtual_destructor.cpp -- 虚析构函数的重要性
#include <iostream>

class Base
{
public:
    Base()  { std::cout << "Base 构造" << std::endl; }

    // ❌ 非虚析构函数(危险!)
    // ~Base() { std::cout << "Base 析构" << std::endl; }

    // ✅ 虚析构函数(正确!)
    virtual ~Base()
    {
        std::cout << "Base 析构" << std::endl;
    }
};

class Derived : public Base
{
private:
    int* data;

public:
    Derived()
    {
        data = new int[100];
        std::cout << "Derived 构造(分配内存)" << std::endl;
    }

    ~Derived()
    {
        delete[] data;   // 释放内存
        std::cout << "Derived 析构(释放内存)" << std::endl;
    }
};

int main()
{
    std::cout << "--- 通过派生类指针删除(正确)---" << std::endl;
    Derived* dp = new Derived();
    delete dp;   // 调用 Derived::~Derived() 然后 Base::~Base()

    std::cout << "\n--- 通过基类指针删除 ---" << std::endl;
    Base* bp = new Derived();
    delete bp;
    // 有虚析构函数:先调用Derived::~Derived(),再调用Base::~Base() ✅
    // 无虚析构函数:只调用Base::~Base(),内存泄漏!❌

    return 0;
}

⚠️ 规则只要类中有虚函数,就必须将析构函数声明为虚函数!

否则通过基类指针 delete 派生类对象时,派生类的析构函数不会被调用,导致资源泄漏。


13.7 override 和 final(C++11)

cpp 复制代码
// override_final.cpp -- override和final关键字
#include <iostream>

class Base
{
public:
    virtual void func1() const { std::cout << "Base::func1" << std::endl; }
    virtual void func2()       { std::cout << "Base::func2" << std::endl; }
    virtual void func3() const { std::cout << "Base::func3" << std::endl; }
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    // ✅ override:明确表示重写虚函数,编译器会检查
    void func1() const override
    {
        std::cout << "Derived::func1" << std::endl;
    }

    // ❌ 没有override时,签名不匹配会静默创建新函数(常见bug)
    // void func2() const { ... }  // 这是新函数,不是重写!

    // ✅ 正确重写
    void func2() override
    {
        std::cout << "Derived::func2" << std::endl;
    }

    // final:禁止进一步重写
    void func3() const override final
    {
        std::cout << "Derived::func3(不可再重写)" << std::endl;
    }
};

// final类:禁止继承
class FinalClass final : public Base
{
public:
    void func1() const override
    {
        std::cout << "FinalClass::func1" << std::endl;
    }
};

// class CannotInherit : public FinalClass {};  // ❌ 错误!

int main()
{
    Derived d;
    Base* p = &d;
    p->func1();   // Derived::func1
    p->func2();   // Derived::func2
    p->func3();   // Derived::func3

    return 0;
}

13.8 动态类型转换

cpp 复制代码
// dynamic_cast.cpp -- 动态类型转换
#include <iostream>
#include <string>

class Animal
{
public:
    virtual std::string type() const { return "Animal"; }
    virtual ~Animal() {}
};

class Dog : public Animal
{
public:
    std::string type() const override { return "Dog"; }
    void fetch() const { std::cout << "去捡球!" << std::endl; }
};

class Cat : public Animal
{
public:
    std::string type() const override { return "Cat"; }
    void purr() const { std::cout << "呼噜呼噜..." << std::endl; }
};

int main()
{
    using namespace std;

    Animal* animals[] = {new Dog(), new Cat(), new Dog()};

    for (int i = 0; i < 3; i++)
    {
        cout << "类型:" << animals[i]->type() << endl;

        // dynamic_cast:安全的向下转型
        // 成功返回有效指针,失败返回nullptr
        if (Dog* dog = dynamic_cast<Dog*>(animals[i]))
        {
            cout << "  这是狗:";
            dog->fetch();
        }
        else if (Cat* cat = dynamic_cast<Cat*>(animals[i]))
        {
            cout << "  这是猫:";
            cat->purr();
        }
    }

    for (auto& a : animals)
        delete a;

    return 0;
}

13.9 多层继承

cpp 复制代码
// multi_level.cpp -- 多层继承示例
#include <iostream>
#include <string>

// 第一层
class Vehicle
{
protected:
    std::string brand;
    int         year;

public:
    Vehicle(const std::string& b, int y)
        : brand(b), year(y) {}

    virtual void show() const
    {
        std::cout << "品牌:" << brand << " 年份:" << year;
    }

    virtual ~Vehicle() {}
};

// 第二层
class Car : public Vehicle
{
protected:
    int doors;

public:
    Car(const std::string& b, int y, int d)
        : Vehicle(b, y), doors(d) {}

    void show() const override
    {
        Vehicle::show();   // 调用基类方法
        std::cout << " 车门:" << doors;
    }
};

// 第三层
class ElectricCar : public Car
{
private:
    int batteryCapacity;   // 电池容量(kWh)

public:
    ElectricCar(const std::string& b, int y,
                int d, int battery)
        : Car(b, y, d), batteryCapacity(battery) {}

    void show() const override
    {
        Car::show();   // 调用父类方法
        std::cout << " 电池:" << batteryCapacity << "kWh" << std::endl;
    }

    int getRange() const { return batteryCapacity * 6; }   // 估算续航
};

int main()
{
    using namespace std;

    ElectricCar tesla("Tesla", 2024, 4, 100);
    tesla.show();
    cout << "估算续航:" << tesla.getRange() << " km" << endl;

    // 多态
    Vehicle* v = &tesla;
    v->show();   // 调用ElectricCar::show()

    return 0;
}

13.10 综合示例:员工管理系统

cpp 复制代码
// employee_system.cpp -- 综合示例:员工管理系统
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>

// ===== 基类:员工 =====
class Employee
{
protected:
    std::string name;
    int         id;
    double      baseSalary;

    static int nextId;

public:
    Employee(const std::string& n, double salary)
        : name(n), baseSalary(salary)
    {
        id = nextId++;
    }

    virtual ~Employee() {}

    // 纯虚函数:每种员工计算薪资的方式不同
    virtual double calcSalary() const = 0;
    virtual std::string getType() const = 0;

    // 普通虚函数
    virtual void show() const
    {
        std::cout << std::setw(4) << id
                  << " | " << std::setw(8) << getType()
                  << " | " << std::setw(10) << name
                  << " | 薪资:" << std::fixed
                  << std::setprecision(2) << calcSalary();
    }

    std::string getName() const { return name; }
    int         getId()   const { return id; }
};

int Employee::nextId = 1001;

// ===== 派生类1:全职员工 =====
class FullTimeEmployee : public Employee
{
private:
    double bonus;   // 奖金

public:
    FullTimeEmployee(const std::string& n,
                     double salary, double b = 0)
        : Employee(n, salary), bonus(b) {}

    double calcSalary() const override
    {
        return baseSalary + bonus;
    }

    std::string getType() const override { return "全职"; }

    void setBonus(double b) { bonus = b; }
};

// ===== 派生类2:兼职员工 =====
class PartTimeEmployee : public Employee
{
private:
    double hourlyRate;   // 时薪
    int    hoursWorked;  // 工作小时数

public:
    PartTimeEmployee(const std::string& n,
                     double rate, int hours)
        : Employee(n, rate), hourlyRate(rate), hoursWorked(hours) {}

    double calcSalary() const override
    {
        return hourlyRate * hoursWorked;
    }

    std::string getType() const override { return "兼职"; }
};

// ===== 派生类3:销售员工 =====
class SalesEmployee : public Employee
{
private:
    double salesAmount;      // 销售额
    double commissionRate;   // 提成比例

public:
    SalesEmployee(const std::string& n,
                  double base, double rate)
        : Employee(n, base), salesAmount(0), commissionRate(rate) {}

    void setSales(double amount) { salesAmount = amount; }

    double calcSalary() const override
    {
        return baseSalary + salesAmount * commissionRate;
    }

    std::string getType() const override { return "销售"; }

    void show() const override
    {
        Employee::show();
        std::cout << " 销售额:" << salesAmount;
    }
};

// ===== 管理类 =====
class Department
{
private:
    std::string          name;
    std::vector<Employee*> employees;

public:
    Department(const std::string& n) : name(n) {}

    ~Department()
    {
        for (auto& e : employees)
            delete e;
    }

    void addEmployee(Employee* e)
    {
        employees.push_back(e);
    }

    void showAll() const
    {
        using namespace std;
        cout << "\n===== " << name << " 部门员工 =====" << endl;
        cout << string(60, '-') << endl;
        double total = 0;
        for (const auto& e : employees)
        {
            e->show();
            cout << endl;
            total += e->calcSalary();
        }
        cout << string(60, '-') << endl;
        cout << "部门总薪资:" << fixed << setprecision(2)
             << total << endl;
    }

    // 找最高薪资员工
    Employee* getHighestPaid() const
    {
        if (employees.empty()) return nullptr;
        Employee* best = employees[0];
        for (const auto& e : employees)
            if (e->calcSalary() > best->calcSalary())
                best = e;
        return best;
    }
};

int main()
{
    using namespace std;

    Department dept("技术");

    // 添加不同类型的员工
    auto* ft1 = new FullTimeEmployee("张三", 15000, 3000);
    auto* ft2 = new FullTimeEmployee("李四", 18000, 5000);
    auto* pt1 = new PartTimeEmployee("王五", 80, 120);
    auto* sl1 = new SalesEmployee("赵六", 8000, 0.05);
    sl1->setSales(200000);

    dept.addEmployee(ft1);
    dept.addEmployee(ft2);
    dept.addEmployee(pt1);
    dept.addEmployee(sl1);

    dept.showAll();

    Employee* best = dept.getHighestPaid();
    if (best)
        cout << "\n最高薪资员工:" << best->getName()
             << "(" << best->getType() << ")"
             << " 薪资:" << best->calcSalary() << endl;

    return 0;
}

输出:

复制代码
===== 技术 部门员工 =====
------------------------------------------------------------
1001 |     全职 |       张三 | 薪资:18000.00
1002 |     全职 |       李四 | 薪资:23000.00
1003 |     兼职 |       王五 | 薪资:9600.00
1004 |     销售 |       赵六 | 薪资:18000.00 销售额:200000
------------------------------------------------------------
部门总薪资:68600.00

最高薪资员工:李四(全职) 薪资:23000

📝 第13章知识点总结

知识点 核心要点
继承语法 class 派生类 : public 基类,派生类拥有基类所有成员
构造/析构顺序 构造:先基类后派生类;析构:先派生类后基类
访问控制 public继承:public→public,protected→protected,private不可访问
虚函数 virtual 关键字,通过基类指针/引用实现运行时多态
虚函数表 每个含虚函数的类有vtable,对象通过vptr找到正确函数
虚析构函数 含虚函数的类必须有虚析构函数,否则delete基类指针会内存泄漏
纯虚函数 = 0,派生类必须实现,含纯虚函数的类是抽象类,不能实例化
override C++11,明确表示重写虚函数,编译器检查签名是否匹配
final C++11,禁止虚函数被进一步重写,或禁止类被继承
dynamic_cast 安全的向下转型,失败返回nullptr(指针)或抛出异常(引用)
多态条件 基类指针/引用 + 虚函数 + 派生类重写
抽象类 含纯虚函数,不能实例化,定义接口规范
相关推荐
我材不敲代码1 小时前
Python基础: 函数超全详解:定义、参数、返回值、作用域与递归
开发语言·python·算法
承渊政道1 小时前
Linux系统学习【进程控制:进程创建、终止与等待、进程程序替换、自主shell命令行解释器详解】
linux·服务器·c++·学习·ubuntu·bash·远程工作
志起计算机编程1 小时前
挖掘单节点Clickhouse极致性能上限
服务器·开发语言·python
Reisentyan1 小时前
[Pro]GoLang Learn Data Day 5
开发语言·后端·golang
zhangfeng11331 小时前
华为昇腾910A NPU 的模型加密方案 ASCEND-CC
开发语言·人工智能·神经网络·transformer
雪度娃娃1 小时前
转向现代C++——优先选用删除函数而非private未定义函数
java·jvm·c++
聆风吟º1 小时前
【Python编程日志】Python基础语法:常量 | 表达式 | 变量
开发语言·python·变量·常量·表达式
QiLinkOS1 小时前
发明人与专利价值共生逻辑
c语言·数据结构·c++·人工智能·单片机·嵌入式硬件·算法
凯瑟琳.奥古斯特1 小时前
10道数据库原理精选题
开发语言·数据库·职场和发展·数据库开发