- private(class默认访问方式):仅定义该成员的类内部可以访问
- protected:派生类可以访问,类外部不可以访问
- public(struct默认访问方式):均可访问
派生类可以通过访问方式对基类成员的访问方式进行改造:
1)private(私有继承):只有定义该成员的类内部可以访问,不允许派生类访问(不论是什么继承方式)。
2)protected(保护继承):基类除了private成员,在派生类中的访问方式均为protected。
3)public(公有继承):基类除了private成员,在派生类中的访问控制与基类一致。
(三)派生类生成的过程: 1)吸收基类成员派生类会除了基类的构造函数、析构函数以外的所有数据成员和函数成员。
2)改造基类成员通过访问方式,数据和函数成员的覆盖对基类成员进行改造。
3)添加新成员尤其是添加构造函数和析构函数
(四)派生类的构造和析构函数- 派生类没有继承基类的构造和析构函数
- 派生类必须对新增的成员初始化,还需要初始化基类的成员
派生类名(参数表):需要初始化的基类名(参数表),新增成员初始化列表 { 构造函数体 }
【PS】:若没有在派生类构造函数中显示初始化基类,则默认调用基类的无参构造函数(此时需基类有无参构造函数)
2)派生类构造函数的执行顺序:1、调用基类的构造函数(按继承时说明从左到右的顺序,与初始化列表无关)
2、(如果有的话)调用子对象的构造函数(按类中说明的顺序)
3、执行派生类构造函数的函数体
执行析构函数的顺序与此正好相反
代码示例:
#includeusing namespace std; class Base { private: int bi; //私有成员 public: Base() { bi=0; cout<<"执行基类Base的构造函数n"; } ~Base() { cout<<"执行基类Base["< (五)派生类的拷贝构造函数 //派生类的拷贝构造函数的一般格式如下: Derived(const Derived &d):Base(d) { //用派生类的引用去初始化基类的引用合法! //正常的派生类的拷贝构造函数体 }//Base:基类,Derived:派生类(六)基类和派生类指针
派生类的成员函数将覆盖基类的所有同名成员函数(含重载的同名函数)。
【注意1】:覆盖不是重载,可以通过**Base::show()**来限定。
【注意2】:若是通过基类指针指向派生类,调用同名函数,则执行的基类的函数。(基类指针不知道派生类新增成员的存在)。
这也引出了一个问题——【为什么要有虚函数?】:
正是由于【注意点2】所说,基类指针只能调用基类成员函数,而不能调用派生类中的新增成员函数,如果使用虚函数,就能够实现用基类指针访问派生类的成员函数,基于这一点,派生类中的这个成员函数和基类的虚函数的形式要完全相同,并且在派生类中实现重写(一个接口多种方法)。
不能通过基类的对象(或指针)访问派生类新增的(共有)成员。
【例1】:
#includeusing namespace std; class Base { public: void print(int a=0) { cout<<"Print in Base"< print(); //执行基类的print,基类指针并不知道派生类中的新增函数 //bp->showDerived(); 报错,理由同上、 } //输出结果如下:
派生类指针不能直接指向基类对象(编译报错),否则可能会使用派生类中的新增成员(在基类中是未定义的),即使是强制转化成基类指针也是调用派生类的函数。
总之,派生类指针无法访问基类成员。
基类指针指向派生类是安全的,但是只能用来调用基类的成员。
若要访问派生类的新增成员,需要进行强制转化。
((Derived *)bp)->print(); //调用的是派生的print(强制转化后,相当于是一个派生类指针,可以访问派生类成员函数) //外面的括号不能省略!!(优先级问题!!)
【例2】派生类和基类指针的相互转化
//派生类和基类指针的相互转化 #include(七)虚基类 1)概念与声明方式using namespace std; class Base { public: void print() { cout<<"Print in Base"< print(); //派生类指针指向基类---报错 // dp=&bObj; //将基类地址赋给派生类需要进行强制转化!! dp=(Derived *)&bObj; dp->print(); dp->show(); } 虚基类(在访问方式前加virtual)
在多层次继承中,若直接基类派生自同一个间接基类,会有两份的间接基类成员。
在虚基类机制下,虽然被一个派生类间接地多次继承,但派生类只继承一份该基类的成员。
2)虚基类下构造函数的执行顺序:1、直接基类中的虚基类的构造函数在非虚基类之前调用
2、多个虚基类按继承时说明从左到右的顺序执行
3、若虚基类由非虚基类派生而来,则仍先调用基类构造函数,再按派生类中的构造函数的执行顺序调用
4、执行派生类构造函数的函数体执行析构函数的顺序与此正好相反
3)初始化派生类
- 对于非虚基类,在派生类的构造函数中初始化间接基类是不允许的;
- 而对于虚基类,则必须在派生类中对虚基类初始化。
例如person是teacher和student的虚基类,则在派生类assistant的构造函数一定要初始化虚基类。
若person不是teacher和student的虚基类,则不允许派生类assistant初始化间接基类person。
注意:虚基类并不是在声明基类时声明的,而是在声明派生类是,指定继承方式时声明的。因为一个基类可以在生成一个派生类作为虚基类,而在生成另一个派生类时不作为虚基类。



