C++回顾day02---<继承相关问题> 一:继承和组合混搭时,构造和析构调用原则 二:继承中的同名成员变量处理方法《重点:同java》 三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问) 四:C++可以多继承(不常用:复杂大于便利) 五:虚继承

(一)先构造父类,再构造成员变量,最后构造自己

(二)先析构自己,再析构成员变量,最后父类析构(方向与构造相反)

class A
{
public:
    int age;
public:
    A(int a)
    {
        cout << "A construct:" << a << endl;
        this->age = a;
    }

    ~A()
    {
        cout << "A distruct:" << age << endl;
    }
};


class B :public A
{
public:
    B(int a, int a2, int a3) :A(a), fri1(a2), fri2(a3)    //最后先父类后组合,顺序可以变
    {
        cout << "B construct:" << age <<endl;    //父类先初始化,所以这里可以直接使用age
    }

    void getInfo()
    {
        cout << this->age << endl;
        cout << this->fri1.age << endl;
        cout << this->fri2.age << endl;
    }

    ~B()
    {
        cout << "B distruct:" << age << endl;
    }

private:
    A fri1, fri2;
};

void test()
{
    B b(10, 11, 12);
    b.getInfo();
}

void main()
{
    test();
    system("pause");
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

二:继承中的同名成员变量处理方法《重点:同java》

(一)当子类成员变量和父类成员变量同名是,子类依旧会从父类继承同名成员

(二)在子类中通过作用域分辨符::进行同名成员区分(显示的使用类名限定符)

(三)同名成员存储在内存中不同位置

class A
{
public:
    int age = 10;
};


class B :public A
{
public:
    int age = 11;

    void getInfo()
    {
        cout << &age << ":" << age << endl;
        cout << &(A::age) << ":" << A::age << endl;
    }
};

void test()
{
    B b;
    b.getInfo();
}

void main()
{
    test();
    system("pause");
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)

#include <iostream>

using namespace std;

class A
{
protected:
    int a;
public:
    A(int b)
    {
        a = b;
        cout << "A construct" << endl;
    }

    void getInfo()
    {
        cout << "this A func" << endl;
    }
};

class B1 :public A
{
public:
    B1(int b) :A(b)
    {
        cout << "B1 construct" << endl;
    }

    void getInfo()
    {
        cout << "this B1 func" << endl;
        A::getInfo();    //1.使用作用域分辨符访问父类函数
    }
};



void main()
{
    B1 b(5);
    b.getInfo();
    A* a = &b;    //2.多态实现调用父类函数
    a->getInfo();
    system("pause");
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

四:C++可以多继承(不常用:复杂大于便利)

class 派生类名 : 访问控制 基类名1, 访问控制 基类名2, 访问控制 基类名3, ...  ,访问控制 基类名n  //父类构造函数执行顺序取决这里的声明
{
    数据成员和成员函数声明
}
class A
{
public:
    A()
    {
        cout << "A" << endl;
    }

};

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

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

class B :public A, public A3, public A2
{
public:
    B()
    {
        cout << "B" << endl;
    }
};

void test()
{
    B b;
}

void main()
{
    test();
    system("pause");
}
多继承构造函数执行顺序:取决于定义继承基类的顺序

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

class A
{
public:
    A(int a) :age(a)
    {
        cout << "A" << endl;
    }

private:
    const int age;
};

class A2
{
public:
    A2(int a) :age(a)
    {
        cout << "A2" << endl;
    }

private:
    const int age;
};

class A3
{
public:
    A3(int a) :age(a)
    {
        cout << "A3" << endl;
    }

private:
    const int age;
};

class B :public A, public A3, public A2
{
public:
    B(int b, int a1, int a2, int a3) :age(b), A(a1), A2(a2), A3(a3)
    {
        cout << "B" << endl;
    }

private:
    const int age;
};

void test()
{
    B b(3,4,5,6);
}
即便与构造函数父类构造顺序不同,实际父类执行顺序还是按照定义声明顺序

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

(一)多继承二义性的两种情况:

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

五:虚继承

(一) 问题引出:如果一个派生类从多个基类派生,而这些基类又有同一个基类,则对该基类中声明的名字就行访问时,可能产生二义性

class A
{
public:
    int age;
public:
    A(int a) :age(a)
    {
        cout << "A" << endl;
    }
};

class A2:public A
{
public:
    int age2;
public:
    A2(int a) :A(a)
    {
        cout << "A2" << endl;
        this->age2 = a;
    }
};

class A3:public A
{
public:
    int age3;
public:
    A3(int a) :A(a)
    {
        cout << "A3" << endl;
        this->age3 = a;
    }
};

class B :public A3, public A2
{
public:
    B(int a2, int a3) :A2(a2), A3(a3)
    {
        cout << "B" << endl;
    }

    void getErr()
    {
        cout << age << endl;
    }
};

void test()
{
    B b(5,6);
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

(二)问题解决:将这个基类设置为虚基类,只产生一个子对象

#include <iostream>

using namespace std;

class A
{
protected:
    int a;
public:
    A()
    {
        a = 10;
    }
};

class B1 : virtual public A
{
public:
    B1()
    {
        cout << a << endl;
    }
};

class B2 :virtual public A
{
public:
    B2()
    {
        cout << a << endl;
    }
};

class C :public B1, public B2
{
public:
    C()
    {
        cout << a << endl;
    }
};

void main()
{
    C Cobj;
    system("pause");
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

(三)补充:虚基类的初始化

调用派生类构造函数的顺序应该坚持的原则:

1.虚基类的构造函数再非虚基类的前面调用
2.若是同一层次包含多个虚基类,这些虚基类的构造函数按照他们说明的顺序调用
3.若虚基类有非虚基类派生而来,则依然遵守先调用基类构造函数再调用派生类中构造函数的执行顺序
#include <iostream>

using namespace std;

class Base1
{
public:
    Base1()
    {
        cout << "Base1 construct" << endl;
    }
};

class Base2 
{
public:
    Base2()
    {
        cout << "Base2 construct" << endl;
    }
};

class Level1 :public Base2, virtual public Base1
{
public:
    Level1()
    {
        cout << "Level1 construct" << endl;
    }
};

class Level2 :public Base2, virtual public Base1
{
public:
    Level2()
    {
        cout << "Level2 construct" << endl;
    }
};

class topLevel :public Level1, virtual public Level2
{
public:
    topLevel()
    {
        cout << "topLevel construct" << endl;
    }
};


void main()
{
    topLevel();
    system("pause");
}

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

(四)虚基类成员初始化(其在初始化上更加严格)

class A
{
protected:
    int a;
public:
    A(int b)
    {
        a = b;
        cout << "A construct" << endl;
    }
};

class B1 : virtual public A
{
public:
    B1(int b) :A(b)
    {
        cout << a << endl;
    }
};

class B2 :virtual public A
{
public:
    B2(int b) :A(b)
    {
        cout << a << endl;
    }
};

class C :public B1, public B2
{
public:
    C(int b) :B1(b), B2(b), A(b)
    {
        cout << a << endl;
    }
};

C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则
二:继承中的同名成员变量处理方法《重点:同java》
三:继承中的重写成员函数处理方法(默认将隐藏父类函数,可以通过作用域分辨符访问)
四:C++可以多继承(不常用:复杂大于便利)
五:虚继承

class A
{
protected:
    int a;
public:
    A(int b)
    {
        a = b;
        cout << "A construct" << endl;
    }
};

class B1 :public A
{
public:
    B1(int b) :A(b)
    {
        cout << a << endl;
        cout << "B1 construct" << endl;
    }
};

class B2 :public A
{
public:
    B2(int b) :A(b)
    {
        cout << a << endl;
        cout << "B2 construct" << endl;
    }
};

class C :public B1, public B2
{
public:
    C(int b) :B1(b), B2(b)//, A(b)
    {
        //cout << a << endl;
    }
};
不含虚基类的初始化