重学C++系列之继承

本文详细介绍了C++中的继承概念,包括公有、保护和私有继承,以及单继承和多继承。通过继承,派生类可以重用基类的成员,提高代码复用性。文章还探讨了构造函数和析构函数的调用顺序,基类成员在派生类中的权限变化,并举例展示了不同继承方式下成员的访问规则。此外,还讨论了继承中的影子现象及其影响。

一、什么是继承

        继承是面向对象三大特性之一,C++中,被继承的类称为基类(父类),继承别的类的类成为派生类(子类),继承除了基类的构造函数和析构函数不继承外,其余成员全部继承。在派生类中继承的成员函数可以重写。通过继承,使得派生类拥有基类的成员。

二、为什么要继承

        通过继承,使得派生类拥有基类的成员,这样可以提高代码的可重用性

三、继承的种类,基本语法是什么

        1、按照继承方式可分为公有继承,保护继承,私有继承

        2、按照继承的基类的个数可分为单继承,多继承。 

        3、按照继承的机制可分为普通继承虚继承。

        基本语法如下:不声明继承方式,默认是私有继承。

class 派生类名:[继承方式] 基类名
{
    // 派生类成员声明

}

四、继承的特性

        1、派生类除了基类的构造函数和析构函数不继承外,其余成员都继承。

        2、派生类对基类成员的初始化默认调用的无参构造函数。

        3、构造函数和析构函数调用顺序如下表

构造函数和析构函数调用顺序
情况构造函数析构函数
只有基类和派生类基类 ---> 派生类派生类 ---> 基类
派生类中有内嵌子对象  基类 ---> 内嵌子对象        --->   派生类派生类 ---> 内嵌子对象 ---> 基类
在基类中有内嵌子对象内嵌子对象 ---> 基类         ---> 派生类派生类 ---> 基类 ---> 内嵌子对象

        4、 基类的成员在派生类中的权限属性如下表

基类的成员在派生类中的权限属性
继承方式\成员publicprotectedprivate
公有继承publicprotected不可见
保护继承protectedprotected不可见
私有继承privateprivate不可见

        在继承中,为了不影响成员的隐藏性,又要提供对基类成员的访问效率,可以将基类的成员变量设置为protected。 

        5、继承中的Shadow(影子)现象。

五、案例

1、构造函数和析构函数调用顺序

(1)只有基类和派生类

#include <iostream>

using namespace std;


// 基类
class Base
{
public:
    Base()
    {
        cout << "Base()" << endl;
    }
    ~Base()
    {
        cout << "~Base()" << endl;
    }

};

// 公有继承
class Test:public Base
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test a;


    return 0;
}

(2)派生类中内嵌子对象

#include <iostream>

using namespace std;


class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
};


// 基类
class Base
{

public:
    Base()
    {
        cout << "Base()" << endl;
    }
    
    ~Base()
    {
        cout << "~Base()" << endl;
    }

};

// 公有继承
class Test:public Base
{
    A a;    // 派生类中内嵌子对象
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test a;


    return 0;
}

(3)基类中内嵌子对象

#include <iostream>

using namespace std;


class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
};


// 基类
class Base
{
    A a;    // 基类中内嵌子对象
public:
    Base()
    {
        cout << "Base()" << endl;
    }
    
    ~Base()
    {
        cout << "~Base()" << endl;
    }

};

// 公有继承
class Test:public Base
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

int main()
{
    Test a;


    return 0;
}

        (4)多继承中调用顺序跟继承顺序有关

#include <iostream>

using namespace std;

class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }
};

class B
{
public:
    B()
    {
        cout << "B()" << endl;
    }
    ~B()
    {
        cout << "~B()" << endl;
    }
};


class C
{
public:
    C()
    {
        cout << "C()" << endl;
    }
    ~C()
    {
        cout << "~C()" << endl;
    }
};

// 构造函数初始化顺序是 A, B, C, Test
class Test:public A, public B, public C
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};


int main()
{
    Test a;




    return 0;
}

2、基类的成员在派生类中的权限属性

(1) 通过公有继承后

#include <iostream>

using namespace std;


// 基类
class Base
{
private:
    int base_private;
protected:
    int base_protected;
public:
    int base_public;
    Base(int a = 0, int b = 0, int c = 0)
    {
        // cout << "Base()" << endl;
        this->base_private = a;
        this->base_protected = b;
        this->base_public =c;
    }
    
    ~Base()
    {
        // cout << "~Base()" << endl;
    }

    int getPrivate()const
    {
        return base_private;
    }

};

// 公有继承
class Test:public Base
{
public:
    // 派生类的中基类成员的初始化采用,构造函数参数列表的方式
    Test(int a = 0, int b = 0, int c = 0):Base(a, b, c)
    {
        // cout << "Test()" << endl;
    }
    ~Test()
    {
        // cout << "~Test()" << endl;
    }
    void show()const
    {
        // 基类成员的属性为公有的,公有继承后,保持不变
        cout << "public: " << base_public << endl;
        // 基类成员的属性为保护的,公有继承后,保持不变
        cout << "protected: " << base_protected << endl;
        // 基类成员的属性为私有,公有继承后,在派生类和类外都不可见
        // cout << "private: " << base_private << endl;
        cout << "private: " << getPrivate() << endl;
    }

};

int main()
{
    Test a(1, 10, 100);
    a.show();
    cout << "public: " << a.base_public << endl;    // 公有,类外也可以访问


    return 0;
}

(2) 通过保护继承后

#include <iostream>

using namespace std;


// 基类
class Base
{
private:
    int base_private;
protected:
    int base_protected;
public:
    int base_public;
    Base(int a = 0, int b = 0, int c = 0)
    {
        // cout << "Base()" << endl;
        this->base_private = a;
        this->base_protected = b;
        this->base_public =c;
    }
    
    ~Base()
    {
        // cout << "~Base()" << endl;
    }

    int getPrivate()const
    {
        return base_private;
    }

};

// 保护继承
class Test:protected Base
{
public:
    // 派生类的中基类成员的初始化采用,构造函数参数列表的方式
    Test(int a = 0, int b = 0, int c = 0):Base(a, b, c)
    {
        // cout << "Test()" << endl;
    }
    ~Test()
    {
        // cout << "~Test()" << endl;
    }
    void show()const
    {
        // 基类成员的属性为公有的,保护继承后,属性变成保护
        cout << "public: " << base_public << endl;
        // 基类成员的属性为保护的,保护继承后,保持不变
        cout << "protected: " << base_protected << endl;
        // 基类成员的属性为私有,保护继承后,在派生类和类外都不可见
        // cout << "private: " << base_private << endl;
        cout << "private: " << getPrivate() << endl;
    }

};

int main()
{
    Test a(1, 10, 100);
    a.show();
    // cout << "public: " << a.base_public << endl;    // 保护,类外不可以访问


    return 0;
}

(3) 通过私有承后

#include <iostream>

using namespace std;


// 基类
class Base
{
private:
    int base_private;
protected:
    int base_protected;
public:
    int base_public;
    Base(int a = 0, int b = 0, int c = 0)
    {
        // cout << "Base()" << endl;
        this->base_private = a;
        this->base_protected = b;
        this->base_public =c;
    }
    
    ~Base()
    {
        // cout << "~Base()" << endl;
    }

    int getPrivate()const
    {
        return base_private;
    }

};

// 保护继承
class Test:private Base
{
public:
    // 派生类的中基类成员的初始化采用,构造函数参数列表的方式
    Test(int a = 0, int b = 0, int c = 0):Base(a, b, c)
    {
        // cout << "Test()" << endl;
    }
    ~Test()
    {
        // cout << "~Test()" << endl;
    }
    void show()const
    {
        // 基类成员的属性为公有的,私有继承后,属性变成私有
        cout << "public: " << base_public << endl;
        // 基类成员的属性为保护的,私有继承后,属性变成私有
        cout << "protected: " << base_protected << endl;
        // 基类成员的属性为私有,私有继承后,在派生类和类外都不可见
        // cout << "private: " << base_private << endl;
        cout << "private: " << getPrivate() << endl;
    }

};

int main()
{
    Test a(1, 10, 100);
    a.show();
    // cout << "public: " << a.base_public << endl;    // 私有,类外不可以访问


    return 0;
}

3、继承中的Shadow(影子)现象

        在继承中,当派生类中出现与基类同名成员时,默认指定是派生类中的成员,如果要指定是基类的成员,必须加作用域运算符::,如基类::成员。

        在单继承中,出现影子现象可以编译通过;而在多继承中,出现影子现象编译不通过,产生二义性。

#include <iostream>

using namespace std;

class base
{
private:
    int a;

public:
    base(int a = 0)
    {
        this->a = a;
    }
    void show()
    {
        cout << "base::show()" << endl;
    }
};

class Test:public base
{
public:
    Test(int a = 0):base(a)
    {

    }
    void show()
    {
        cout << "Test::show()" << endl;
    }

};


int main()
{
    Test a(10);
    a.show();   // 调用Test::show()
    a.base::show(); // 调用base::show()

    return 0;
}

六、总结

        本文讲解继承的知识,包括继承的概念,调用构造函数和析构函数的顺序,基类成员在派生类中的权限属性和继承中的影子现象。其实还有虚继承,放在另外一篇讲,感兴趣的搜索左边的目录栏就可以找到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值