C++第四节课

来源:互联网 发布:江边城外 知乎 编辑:程序博客网 时间:2024/05/16 20:37

知识点:三种属性,using改变权限,继承时名字的遮蔽,函数重载的遮蔽问题,派生类的构造函数,多继承类,命名冲突,虚继承,多继承的构造函数,


1

在基类中,基类的public,protected ,private 成员都是可以访问的,但是类的对象只能访问public成员


public继承: 基类的public成员,在派生类中依旧是public属性,派生类的对象可访问以访问;
             基类中的private成员,在派生类中是private属性,派生类中的对象不可以访问;派生类中也不可以访问;
             基类中的protected成员,在派生类中是protected属性,派生类的对象中不可以访问,派生类中是可以访问基类的protected成员的;
private继承:基类中的public成员,在派生类中是private属性;在派生类对象中是不可以访问;基类中public变成派生类中private, 在派生类中是可以访问的;
             基类中private成员,在派生类中是private属性,在派生类和派生对象中都是不可以访问的;
             基类中protected成员,在派生类中是private属性,在派生类中是可以访问的,在派生类的对象中是不可以访问的;
protected继承:  基类中public成员,在派生类中是protected属性,在派生类中是可以直接访问,在派生类对象中无法访问;
                。。。protected 成员,在派生类中protected属性,在派生类中可直接访问,在派生类对象中不能访问;
                基类中private成员,在派生类中private属性,在派生类中无法访问,派生类对象无法访问;
               



小结:

              基类中的private的成员,不管何种继承方式,在派生类和派生对象中都是不可以访问的;

             基类中的protected成员,不管何种继承方式,在派生类中都是可以访问的,在派生类的对象中都是不可以访问的;

             基类中的public成员只有是public继承才能在派生类的对象中访问,当是protected或者private继承时,只能在派生类中访问;


2.

要是派生类想要通过基类中的非private函数访问基类中的private成员,而基类中没有非private函数的时候就只能使用using来在派生类中改变基类在派生类中的权限

使用using改变使用权限;

using可以把public改变成private,protected;

using可以把protected改变成private,public

using不可以改变private的属性


3.继承中不存在重载,只要派生类自己的函数(或者变量)和继承过来的基类函数(或者变量)名字相同的时候,不管类型如何都会发生遮蔽;


4.继承时的内存模型

派生类中的内存时:基类中的变量所占的空间      ++++ 派生类自己的变量的内存空间;

而所有成员函数仍然存储在另外一个区域——代码区,由所有对象共享



5派生类的构造函数

基类的构造函数不能被继承,同时也不能被当成派生类的普通函数进行调用,调用基类的构造函数的时候,函数()内写的是传入的实参,不需要加类型如int,float之类的;

当派生类中需要对基类的private成员继承初始化,但是基类中却没有可以调用private成员的函数,这时候就需要在派生类中调用基类的构造函数;

派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的

也可以将基类构造函数的调用放在参数初始化表后面:
Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }
但是不管它们的顺序如何,派生类构造函数总是先调用基类构造函数再执行其他代码(包括参数初始化表以及函数体中的代码)


6基类的析构函数也不能被继承


7多继承的时候,继承是有顺序的如:

class D:public A,public B,public C(     )

{};

先继承A的内容,再继承B的内容,最后继承C的内容



8命名冲突

当派生类继承的多个基类中有函数名相同,这时候就是命名冲突,编译器会报错

这是后就需要对冲突的函数加上域解析符,显式地指明到底使用哪个类的成员,消除二义性。


9虚继承,在继承方式前面加上 virtual 关键字就是虚继承:也可以消除命名冲突;不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。

class B: virtual public A{  //虚继承

class C: virtual public A{  //虚继承

在虚继承中,虚基类是由最终的派生类初始化的,换句话说,
最终派生类的构造函数必须要调用虚基类的构造函数。
对最终的派生类来说,虚基类是间接基类,而不是直接基类。
这跟普通继承不同,在普通继承中,派生类构造函数中只能
调用直接基类的构造函数,不能调用间接基类的。





D::D(int a, int b, int c, int d): A(a), B(90, b), C(100, c), m_d(d){ }

在最终派生类 D 的构造函数中,除了调用 B 和 C 的构造函数,还调用了 A 的构造函数,这说明 D 不但要负责初始化直接基类 B 和 C,还要负责初始化间接基类 A。
普通继承中:派生类的构造函数只负责初始化它的直接基类,再由直接基类的构造函数初始化间接基类,用户尝试调用间接基类的构造函数将导致错误。


现在采用了虚继承,虚基类 A 在最终派生类 D 中只保留了一份成员变量 m_a,如果由 B 和 C 初始化 m_a,那么 B 和 C 在调用 A 的构造函数时很有可能给出不同的实参,这个时候编译器就会犯迷糊,不知道使用哪个实参初始化 m_a。

C++ 干脆规定必须由最终的派生类 D 来初始化虚基类 A,直接派生类 B 和 C 对 A 的构造函数的调用是无效的



构造函数的执行顺序:
虚继承时构造函数的执行顺序与普通继承时不同:

1.在最终派生类的构造函数调用列表中,不管各个构造函数出现的顺序如何,编译器总是先调用虚基类的构造函数,再按照出现的顺序调用其他的构造函数;

2.对于普通继承,就是按照构造函数出现的顺序依次调用的。