• C++零基础教程(类的继承)



    前言

    本篇文章我们来讲解类的继承,继承在C++中是非常重要的概念,这里需要大家认真的学习一下。

    一、类的组合关系

    类的组合关系是一种在面向对象编程中常见的关系类型,它描述了一个类由其他类的对象作为成员来组成的情况。在组合关系中,一个类包含了其他类的对象作为自己的成员,这些成员对象的生命周期与包含它们的类对象的生命周期相关联。

    组合关系通常用于表示"拥有"的关系,表示一个类作为另一个类的一部分存在。这种关系是一种强耦合的关系,所以在组合关系中,包含类的对象负责创建和销毁其成员对象。

    下面我们以一个简单的代码示例来解释类的组合关系:

    class Engine {
    public:
        void start() {
            // 启动引擎的逻辑
        }
    
        void stop() {
            // 停止引擎的逻辑
        }
    };
    
    class Car {
    private:
        Engine engine;
    
    public:
        void startCar() {
            engine.start();
        }
    
        void stopCar() {
            engine.stop();
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在上述示例中,Engine 类表示一台发动机,它具有启动和停止的功能。Car 类表示一辆汽车,它使用了一个 Engine 对象作为其成员。这里 Car 类与 Engine 类之间存在组合关系,因为 Car 类拥有一个 Engine 对象作为其一部分。

    通过组合关系,Car 类可以在自己的方法中调用 Engine 类的方法,实现了汽车的启动和停止操作。而 Engine 对象的生命周期与 Car 对象的生命周期相关联,当 Car 对象被创建时,Engine 对象也会被创建,并且当 Car 对象被销毁时,Engine 对象也会被销毁。

    总结来说,类的组合关系描述了一个类通过将其他类的对象作为自己的成员来构成的关系,具有强耦合性,成员对象的生命周期与包含它们的类对象相关联。组合关系用于表示"拥有"的关系,允许包含类访问和操作成员对象的功能。

    二、类的继承

    在C++中,继承是一种面向对象编程的重要概念,它允许一个类(称为派生类)继承另一个类(称为基类或父类)的属性和方法。通过继承,派生类可以重用基类的代码,并且可以在不修改基类的情况下添加自己的特定功能。

    C++中的继承分为几种类型:

    1.公有继承(public inheritance):基类的公有成员在派生类中仍然是公有成员,基类的保护成员在派生类中变为保护成员,基类的私有成员在派生类中不可直接访问。公有继承使用关键字public来进行声明。

    2.保护继承(protected inheritance):基类的公有和保护成员在派生类中变为保护成员,基类的私有成员在派生类中不可直接访问。保护继承使用关键字protected来进行声明。

    3.私有继承(private inheritance):基类的所有成员在派生类中都变为私有成员,基类的成员在派生类中不可直接访问。私有继承使用关键字private来进行声明。

    以下是一个简单的C++代码示例来解释继承的概念:

    #include 
    using namespace std;
    
    class Animal {
    protected:
        string name;
    
    public:
        Animal(string name) {
            this->name = name;
        }
    
        void eat() {
            cout << name << " is eating." << endl;
        }
    };
    
    class Dog : public Animal {
    public:
        Dog(string name) : Animal(name) {
        }
    
        void bark() {
            cout << name << " is barking." << endl;
        }
    };
    
    int main() {
        Dog dog("Buddy");
        dog.eat();    // 输出:Buddy is eating.
        dog.bark();   // 输出:Buddy is barking.
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在上述示例中,Animal 类是基类,它有一个受保护的属性 name 表示动物的名字,以及一个公共方法 eat() 表示动物的进食行为。

    Dog 类是派生类,通过关键字 public 继承了 Animal 类。子类可以继承基类的公有和保护成员,因此 Dog 类中可以访问和使用 name 属性和 eat() 方法。此外,Dog 类还新增了一个独有的方法 bark() 表示狗的叫声。

    通过继承,我们在主函数中创建了一个 Dog 对象,并且可以调用其继承自基类的 eat() 方法和派生类新增的 bark() 方法。

    继承的主要优势在于代码重用和扩展性。子类可以重用基类的代码,从而减少了重复编写相似功能的工作,并提高了代码的可维护性。同时,子类可以在继承的基础上添加、修改和重写基类的属性和方法,以满足特定的需求。

    三、父类构造函数和子类构造函数的关系

    创建子类对象时,首先会执行父类的构造函数,然后再执行子类的构造函数。这是因为子类继承了父类的成员,需要先初始化父类的成员,然后再初始化子类自己的成员。

    class Base {
    public:
        Base() {
            // Base类的构造函数实现
            cout << "Base类的构造函数被调用" << endl;
        }
    };
    
    class Derived : public Base {
    public:
        Derived() {
            // Derived类的构造函数实现
            cout << "Derived类的构造函数被调用" << endl;
        }
    };
    
    int main() {
        Derived obj; // 创建Derived类的对象
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    输出结果将会是:

    Base类的构造函数被调用
    Derived类的构造函数被调用
    
    • 1
    • 2

    从输出结果可以看出,创建Derived类的对象时,先调用了Base类的构造函数,然后才调用Derived类的构造函数。

    四、父类析构函数和子类析构函数

    在C++中,析构函数用于释放对象占用的资源,并在对象销毁时执行一些清理操作。当一个对象被销毁时,先调用子类的析构函数,然后再调用父类的析构函数。这是因为派生类继承了父类的成员,需要先释放派生类自己的资源,然后再释放父类的资源。

    父类的析构函数通常被声明为虚函数,以便正确地销毁派生类对象。通过虚函数的多态性,当使用基类指针或引用指向派生类对象时,可以通过基类的指针或引用来销毁对象而调用相应的析构函数。

    下面是一个简单的示例来说明父类析构函数和子类析构函数的调用顺序:

    #include 
    using namespace std;
    
    class Base {
    public:
        Base() {
            cout << "Base类的构造函数被调用" << endl;
        }
    
        virtual ~Base() {
            cout << "Base类的析构函数被调用" << endl;
        }
    };
    
    class Derived : public Base {
    public:
        Derived() {
            cout << "Derived类的构造函数被调用" << endl;
        }
    
        ~Derived() override {
            cout << "Derived类的析构函数被调用" << endl;
        }
    };
    
    int main() {
        Derived obj; // 创建Derived类的对象
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    输出结果将会是:

    Base类的构造函数被调用
    Derived类的构造函数被调用
    Derived类的析构函数被调用
    Base类的析构函数被调用
    
    • 1
    • 2
    • 3
    • 4

    从输出结果可以看出,当创建Derived类的对象时,先调用了Base类的构造函数,然后再调用了Derived类的构造函数。当销毁对象时,先调用了Derived类的析构函数,然后再调用了Base类的析构函数。这个顺序保证了销毁对象的正确性。

    总结

    本篇文章主要讲解到了继承,这个概念需要大家牢牢掌握,在继承中大家需要注意public ,protected,private这三个访问权限的不同区别。

  • 相关阅读:
    使用Django Rest Framework设计与实现用户注册API
    APView500电能质量在线监测装置
    两个移相算法
    电子器件系列57:肖特基二极管(BAS7005)
    Spring Cloud Gateway针对指定接口做响应超时时间限制
    Apple硬件相关
    【考研】时间复杂度与空间复杂度习题练习(含真题)
    【文本分类】《融合注意力和剪裁机制的通用文本分类模型》
    理解 MySQL join 语句的执行过程
    (免费分享)基于springboot博客系统
  • 原文地址:https://blog.csdn.net/m0_49476241/article/details/131758483