继承的相关知识

来源:互联网 发布:回形针淘宝店面设计图 编辑:程序博客网 时间:2024/06/06 05:21

1、 继承的概念:继承是面向对象程序设计使代码可以重复用的最重要的手段,其也是c++的一大特性。程序员在保持原有类特性的基础性上进行扩展,增加功能,产生新的类,称为派生类。被继承的类称为父类或基类。
2、继承的定义格式:
class DeriveClassName:acess-label BaseClassName
DeriveClassName——-派生类(子类)名
acess-label——–继承类型(分为:public、protected、private)
BaseClassName——–基类(父类)名称
3、基类的成员函数或者成员变量有三种类型 :public/protected/private
各继承类型中成员的访问类型变化(在继承中,基类的私有成员继承到派生类中后始终是不可见的)具体如下:
public继承:
“is-a”方式,基类的各类型成员的访问类型不变,基类中继承的私有成员不可见。成员public仍为public、protected仍为protected

protected继承:
“ has-a“方式 , 在受保护继承中,基类的公有成员(public)和受保护成员(protected)继承到派生类中都变成受保护成员,基类中的私有成员通过继承在派生类中不可见。成员public变为protected、protected变为protected

private继承:
“has-a“方式, 在私有继承中, 基类的公有成员(public)和受保护成员(protected)继承到派生类中后都变成私有成员(private),基类中的私有成员在派生类中不可见。成员public变为private、protected变为private。
具体的public继承如下:

#include<iostream>using namespace std;class B{public:    B()    {        cout << "B()" << endl;    }    ~B()    {        cout << "~B()" << endl;    }private:    int _a;};class D :public B //D公有继承了B{public:    int _b;    void Display()    {        cout << _b << endl;    }};int main(){    cout << sizeof(D) << endl;    system("pause");    return 0;}对派生类求大小,以证明基类中的私有成员在派生类中是否存在。如果不存在则大小为4,存在则为8

这里写图片描述
基类私有成员在被派生类继承了,具体可否通过编译请看下图:

#include<iostream>using namespace std;class B{public:    B()    {        cout << "B()" << endl;    }    ~B()    {        cout << "~B()" << endl;    }protected:  int _c;private:    int _a;};class D :public B {public:    int _b;    void Display()    {        cout << _a << endl;        cout << _b << endl;    }};int main(){    cout << sizeof(D) << endl;    system("pause");    return 0;}

这里写图片描述

#include<iostream>using namespace std;class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    b._a1 = 0;    //b._a2 = 1;//不可访问    //b._a = 2;//不可访问    D d;    d._a1 = 0;//B的公有成员可以通过派生类D访问    //d._a2 = 2;//B的保护成员在类外不可访问    //d._a3 = 1;//不可访问    system("pause");    return 0;}

protected继承如下:

#include<iostream>using namespace std;class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :protected B //D protected继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    b._a1 = 0;//可以访问    b._a2 = 1;//不可访问    //b._a = 2;//不可访问    D d;    //d._a1 = 0;//B的公有成员不可以通过派生类D访问    //d._a2 = 2;//B的保护成员在类外不可访问    //d._a3 = 1;//不可访问    system("pause");    return 0;}

private继承:

#include<iostream>using namespace std;class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :private B //D 私有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    b._a1 = 0;//可以访问    b._a2 = 1;//B的保护成员在类外不可访问    //b._a = 2;//B的私有成员在类外不可访问    D d;    //d._a1 = 0;//B的公有成员不可以通过派生类D访问    //d._a2 = 2;//B的保护成员在类外不可访问    //d._a3 = 1;//不可访问    system("pause");    return 0;}

继承关系中的构造函数调用:
构造对象必定涉及到类的构造函数,在继承关系中基类和派生类都有构造函数且基类的构造函数和析构函数是不能继承的,下面来研究其实如何调用的。

class Base{public:    Base()    {        cout << "Base()" << endl;    }    void Display1()    {        _b = 0;        cout << _b << endl;    }    ~Base()    {        cout << "~Base()" << endl;    }private:  int _b;};class Derive :public Base{public:    Derive()    {        cout << "Derive()" << endl;    }    void Display2()    {        _d = 1;        cout << _d << endl;    }    ~Derive()    {        cout << "Derive()" << endl;    }    private:        int _d;};int main(){    Derive d;    d.Display1();    system("pause");    return 0;}

构造函数调用顺序:
基类构造函数->派生类中对象构造函数->派生类构造函数体
派生类析构函数的调用顺序:
派生类析构函数->类内类成员的析构函数(与定义顺序相反)->基类析构函数 的顺序执行的。

继承体系的作用域:
在继承体系中的两个类是两个不同的作用域,它们只能调用自己类里面的成员(基类中的静态成员除外),比如基类对象只能调用基类的成员,而不能调用子类特有的成员,因为类的封装特性,派生类也不能调用基类的私有成员。
赋值兼容原则: 那么如果派生类中的一个成员与基类某个public或protected成员同名,当派生类对象调用这个成员时,到底是调用哪个成员呢?这就涉及到继承关系中同名隐藏问题。

class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D 公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    D d;    d._a1 = 1;//B的公有成员不可以通过派生类D访问    system("pause");    return 0;``}

看具体的内存情况:
这里写图片描述
在赋值操作中调用的是派生类独有的成员,这就发生了同名隐藏,继承关系中基类中的同名成员被派生类成员覆盖,在发生同名隐藏时访问的是基类成员。则在发生同名隐藏时要访问基类成员需在基类成员前加上基类名及域操作符,如下所示:

int main(){    Derive d;    d.Base::_a1 = 1;    d._a1 = 2;    system("pause");    return 0;}

另外: 继承关系中的赋值兼容规则前提必须是public继承,赋值兼容规则具体指:
1、子类对象可以给基类对象赋值(切割/切片)
2、基类对象不能给子类对象赋值。
3、基类的指针/引用可以指向子类对象
4、子类的指针/引用不能指向基类对象(可通过强制类型转换)。

子类给基类赋值:class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D 公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    D d;    d._a1 = 1;    d._b1 = 2;    b = d;    system("pause");    return 0;}

这里写图片描述
基类给子类赋值:

class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D 公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    D d;    b._a1 = 1;    b._b1 = 2;    d = b;    system("pause");    return 0;}

这里写图片描述
所以:子类对象可以给基类对象赋值(切割/切片),基类对象不能给子类对象赋值。

 基类指针指向派生类:class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D 公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    D d;    B*p = &d; //B的公有成员不可以通过派生类D访问    system("pause");    return 0;}  基类指针指向派生类合法。

子类指针指向基类:

class B{public:    int _a1;    B()    {        cout << "B()" << endl;    }             ~B()    {        cout << "~B()" << endl;    }protected:    int _a2;private:    int _a3;};class D :public B //D 公有继承了B{public:    int _b1;    void Display()    {        cout << _a1 << endl;    }protected:    int _b2;private:    int _b3;};int main(){    //cout << sizeof(D) << endl;    B b;    //D d;    D*p = &b; //B的公有成员不可以通过派生类D访问    system("pause");    return 0;}

这里写图片描述
所以:基类的指针/引用可以指向子类对象,子类的指针/引用不能指向基类对象(可通过强制类型转换)。
继承的几个种类:
单继承、多继承
单继承:以上所举例均为单继承
多继承:这里写图片描述
菱形继承
这里写图片描述
具体的菱形继承代码如下:

class B{public:    int _b;};class c1 :public B{public:    int _c1;};class c2 :public b{public:    int _c2;};class D :public c1, public c2{public:    int _d;};int main(){    cout << sizeof(D) << endl;    D d;    d._b = 0;    system("pause");        return 0;}

d._b = 0;在D类中有两个B类的成员,则造成了二义性。
在c++中,提供了一种解决方法——虚基类,使得在继承间接共同基类时只保留一份成员。

class 派生类名:virtual 继承方式 基类名class B{public:    int _b;};class c1 :virtual public B{public:    int _c1;};class c2 :virtual public B{public:    int _c2;};class D :public c1, public c2{public:    int _d;};int main(){    cout << sizeof(D) << endl;    D d;    d._b = 0;    d._c1=1;    d._c2=2;    d._d=4;    system("pause");        return 0;}

菱形继承的内存分布:
这里写图片描述
具体总结如下:
虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。虚拟继承的基类部分在最底下。
虚拟继承的构造函数调用方式为:
派生类–>合成构造函数–>将偏移量表格地址放在对象的前4个字节中
虚拟继承对于继承成员访问形式:
偏移量表格地址–>偏移量表格–>相对于基类对象的偏移量–>访问基类成员

原创粉丝点击