C++ 继承与派生详解:从概念到代码实战

C++ 面向对象编程:继承与派生详解

在 C++ 面向对象编程中,继承 (Inheritance)派生 (Derivation) 是两个核心概念,它们让我们能够实现代码复用、提升程序的扩展性。本文将结合示例代码和讲解图片,带你深入理解继承与派生的机制和使用方法。


1. 继承与派生的基本概念

  • 继承:保持已有类的特性而构造新类的过程。

  • 派生:在已有类的基础上新增自己的特性而产生新类的过程。

在继承体系中:

  • 被继承的类称为 基类 (Base Class 或 父类)

  • 派生出的类称为 派生类 (Derived Class 或 子类)

继承和派生的目的:

  • 继承的目的:实现代码重用,提高扩展性。

  • 派生的目的:当原有程序无法解决新问题时,可以在原有类的基础上扩展功能。


2. 继承方式:public / protected / private

2.1 公有继承 (public)

特点:

  • 基类的 public 成员在子类中保持 public

  • 基类的 protected 成员在子类中保持 protected

  • 基类的 private 成员在子类中不可直接访问。

类外访问:

  • 只能通过子类对象访问基类的 public 成员。

代码示例:

#include <iostream>
using namespace std;

#if 0
class A
{
public:
    void fun_A_public()
    {
        cout << "fun_A_public" << endl;
    }

protected:
    void fun_A_protected()
    {
        cout << "fun_A_protected" << endl;
    }

private:
    void fun_A_private()
    {
        cout << "fun_A_private" << endl;
    }
};

// 继承方式:public、protected、private
// 1、继承方式只影响父类的成员在子类中是否需要改变访问属性,
//    也就是父类中的成员拷贝到子类中后,这些成员在子类中的其存在的访问权限
// 2、子类中是否能够访问基类中的成员,与继承方式是没有关系的。
//    子类中是否能访问基类中的成员,只与原基类中成员访问权限有关,
//    父类中的private成员子类无法访问,public、protected成员是可以直接访问。
class B : public A
{
public:
    void fun_B_public()
    {
        cout << "fun_B_public" << endl;

        // 子类中可以直接调用或访问父类中的public、protected成员,
        // 不需要使用类对象访问,因为继承本质就是我子类复用了基类的代码。
        fun_A_public();
        fun_B_private();

        // 子类中无法访问父类中的private成员
       // fun_A_private();
        fun_A_protected();
    }
      
protected:
    void fun_B_protected()
    {
        cout << "fun_B_protected" << endl;
        fun_A_protected();
    }

private:
    void fun_B_private()
    {
        cout << "fun_B_private" << endl;
    }

};



int main(int argc, char *argv[])
{
    B b;

    // 1、父类中的public成员,在使用public方式继承时,
    //    其可以通过子类对象,在类的外部直接访问。
    // 2、无论是什么继承方式,父类中的protected、private成员,在类外部都无法访问。
    b.fun_A_public();
    b.fun_B_public();
  
    
      

2.2 保护继承 (protected)

特点:

  • 基类的 public 成员在子类中变为 protected

  • 基类的 protected 成员依然是 protected

  • 基类的 private 成员依然不可访问。

类外访问:

  • 子类对象无法直接访问从基类继承的 public 成员,只能在子类内部访问。

2.3 私有继承 (private)

特点:

  • 基类的 publicprotected 成员在子类中都变为 private

  • 基类的 private 成员依然不可访问。

类外访问:

  • 子类对象无法直接访问继承的成员。


3. 构造与析构顺序

在 C++ 中,当类之间存在组合或继承关系时,构造和析构的调用顺序尤为重要。

3.1 组合关系

#include <iostream>
using namespace std;

class A
{
public:
    A();//无参构造
    A(int a, int b);//带参构造
    ~A();

private:
    int m_AA;
    int m_AB;
};

class C
{
public:
    C(int a);
    ~C();

private:
    int m_C;
};
//当创建一个“容器”类的对象时(这里是B),会首先构造它的成员变量,然后才执行它自身的构造函数体。成员变量的构造顺序严格按照它们在类中声明的顺序,与它们在构造函数初始化列表中的顺序无关。
class B
{
public:
    B(int b, int c);
    ~B();

private:
    C ccc;
    A aaa;    // 类组合关系
    int m_B;
};

A::A()
{
    cout << "A construct" << endl;
}

A::A(int a, int b) : m_AA(a), m_AB(b)
{
    cout << "A construct: " << m_AA << " : " << m_AB << endl;
}

A::~A()
{
    cout << "A descstruct: " << m_AA << " : " << m_AB << endl;
}

// 类组合时,当前类负责初始化构造组合类
// 原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。
// 如果A类是无参构造,那么可以不用管,系统会自动调用其无参构造
// 如果我们需要使用A类的带参构造,那么B类必须负责A类的构造
B::B(int b, int c) : ccc(b), aaa(b, c), m_B(c)
{
    // 不允许访问组合类中的私有成员
    //aaa.m_AA = 11112;
    cout << "B construct: " << m_B << endl;
}

B::~B()
{
    cout << "B descstruct: " << m_B << endl;
}

C::C(int a) : m_C(a)
{
   cout << "C construct: " << m_C << endl;
}

C::~C()
{
    cout << "C descstruct: " << m_C << endl;
}

int main(int argc, char *argv[])
{
    // 在拥有组合关系时,当前B类中有一个A类对象的成员变量
    // 其构造顺序:
    // 1、先构造B的成员变量,但是由于成员变量中拥有A类对象
    // 2、所以调转至A类进行构造,先构造其成员变量
    // 3、在执行A类的构造函数
    // 4、返回B类,如果有未构造的其它成员变量,继续构造
    // 5、最后在执行B类构造函数
    B b(123, 456);

    return 0;
}

执行顺序:

  1. 先构造 B 的成员变量(CA)。

  2. 然后执行 B 的构造函数。

  3. 析构时顺序相反:先析构 B 自身,再析构其成员。

3.2 继承关系

class A {
public:
    A(double val) { cout << "A construct with value: " << val << endl; }
    ~A() { cout << "A destruct" << endl; }
};

class B : public A {
public:
    B(double n) : A(n) { cout << "B construct" << endl; }
    ~B() { cout << "B destruct" << endl; }
};

int main() {
    B myB(99.5);
    return 0;
}

执行顺序:

  1. 先调用基类 A 的构造函数。

  2. 再执行派生类 B 的构造函数。

  3. 析构顺序相反:先析构 B,再析构 A。


4. 内部访问与外部访问

派生类可以访问基类的 publicprotected 成员,但不能访问 private 成员。下面是派生类内部函数 show_all_internal_access 的示例:

void show_all_internal_access() {
    cout << "--- Inherited from A ---" << endl;
    fun_A_public();      // ✅ 可访问
    fun_A_protected();   // ✅ 可访问
    // fun_A_private();   // ❌ 不可访问

    cout << "--- B's Own Members ---" << endl;
    fun_B_public();      // ✅ 可访问
    fun_B_protected();   // ✅ 可访问
    fun_B_private();     // ✅ 可访问
}

5. 总结

  • 继承派生是 C++ 面向对象编程的基石。

  • public / protected / private 继承方式决定了基类成员在子类中的可见性和访问权限。

  • 构造与析构顺序遵循 先基类 → 后子类析构顺序相反 的原则。

  • 子类内部能访问基类的 publicprotected,但不能访问 private

通过理解这些规则,我们就能写出更清晰、更易维护的 C++ 面向对象代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值