标签:font 影响 style 绑定 通过 过程 mes 类的声明 一个
类的继承的概念
继承是在保持已有类的基础之上构造新类的过程,而派生是指在已有类的基础之上新增自己的特性而产生新类的过程。二者是对同一个问题的不同描述,继承侧重于保持原有类的特性,而派生侧重于增加新的特性。被继承的类(即原有类)称为基类,派生出的类称为派生类。基类又分为直接基类和间接基类。
继承的目的:实现设计与代码的重用
派生的目的:对原有的类进行改造以解决基类不能解决的问题。当基类中已有的函数核成员不能够解决现有的问题时,那么我们需要新增数据成员或者函数成员以解决这个问题。
单继承时派生类的定义:
Class 派生类名:继承方式 基类名
{
成员声明;
}
多继承时派生类的定义:
Class 派生类名:继承方式1 基类名1,继承方式2 基类名…
{
成员声明;
}
默认情况下,派生类包含了全部基类中除了构造和析构函数之外的所有成员,不过c++11标准中也提供了使用using语句将基类的构造函数也继承过来的功能。如果在派生类中声明了与基类中同名的新成员,那么基类中的成员就会被覆盖。
继承方式
不同继承方式的影响主要体现在这两个方面,一方面继承方式会决定派生类的成员对基类成员的访问权限,另一方面决定了派生类的对象对基类成员的访问权限。继承方式有三种:公有继承,私有继承,保护继承。三种继承方式的特性见下表:
私有继承(private)
保护继承(protected)
protected 成员的特点与作用
类型转换
通过公有派生类的对象可以当作基类的对象使用,反之不然。派生类的对象可以隐含转换为基类对象,派生类对象可以初始化基类的引用,派生类的指针可以隐含转换为基类的指针。通过基类对象名、指针只能使用从基类继承来的成员。不要重新定义继承而来的非虚函数。
案例代码:
#include <iostream>
using namespace std;
class Base1 { //基类Base1定义
public:
void display() const {
cout << "Base1::display()" << endl;
}
};
class Base2: public Base1 { //公有派生类Base2定义
public:
void display() const {
cout << "Base2::display()" << endl;
}
};
class Derived: public Base2 { //公有派生类Derived定义
public:
void display() const {
cout << "Derived::display()" << endl;
}
};
void fun(Base1 *ptr) { //参数为指向基类对象的指针
ptr->display(); //"对象指针->成员名"
}
int main() { //主函数
Base1 base1; //声明Base1类对象
Base2 base2; //声明Base2类对象
Derived derived; //声明Derived类对象
fun(&base1); //用Base1对象的指针调用fun函数
fun(&base2); //用Base2对象的指针调用fun函数
fun(&derived); //用Derived对象的指针调用fun函数
return 0;
}
运行这个程序我们会发现:打印的结果一直为Base1::display(),这是为什么呢?在后面我们会学到:如果在派生类中有与基类中同名的函数,那么需要在基类中将这个函数定义为虚函数,在派生类中也定义为虚函数,因为非虚函数在编译的时候是静态的,不能够实现动态绑定,而虚函数在编译的时候先不去编译具体的函数体,而是在运行的时候才确定执行哪一段函数代码,这样我们就可以实现通用的打印函数了。
派生类的构造函数
默认情况下,基类的构造函数不被继承,派生类需要定义自己的构造函数。C++11中规定:可以用using语句继承基类的构造函数,但是只能初始化从基类继承的成员,如果派生类有新增的数据成员,那么继承来的构造函数是不能对新增的数据成员初始化的。语法格式:using B::B;如果不去继承基类的构造函数,那么派生类的新增成员需要通过派生类中定义的构造函数初始化,继承自基类的成员会自动地调用基类的构造函数进行初始化,但是基类的构造函数的参数从哪里传递进去呢?这时,我们需要通过派生类的构造函数给基类的构造函数传递参数。单继承时构造函数的定义语法:
派生类名::派生类名(基类需要的形参,本类成员需要的形参):
基类名(参数表), 本类成员初始化列表
{
//其他初始化;
};
多继承时构造函数:
派生类名::派生类名(形参表):
基类名1(参数),基类名2(参数),…基类名n(参数)
{
//其他初始化;
};
派生类与基类的构造函数
当基类有默认构造函数时
? 派生类构造函数可以不向基类构造函数传递参数。
? 构造派生类的对象时,基类的默认构造函数将被调用。
如需执行基类中带参数的构造函数
? 派生类构造函数应为基类构造函数提供参数
多继承且有对象成员时派生的构造函数定义语法
派生类名::派生类名(形参表):
基类名1(参数), 基类名2(参数), ..., 基类名n(参数),
本类成员(含对象成员)初始化列表
{
//其他初始化
};
构造函数的执行顺序
第一步,调用基类构造函数,其顺序按照他们被继承时的顺序;第二步,对初始化列表中的成员进行初始化,对象成员初始化时自动调用其所属类的构造函数;第三步,执行派生类中的构造函数体中的内容。
派生类的复制构造函数
派生类的析构函数
派生类如果需要析构函数,则我们需要自己定义析构函数,其声明方法与无继承关系的类的析构函数相同,析构函数不需要显示调用。在执行析构函数时,系统会先执行派生类的析构函数,再调用基类析构函数。
访问从基类中继承的成员
当派生类中定义有与基类相同名称的成员时,在没有特别限定的情况下,通过派生类的对象使用的是派生类中的同名成员,如果要通过派生类对象访问基类中被隐藏的成员,则需要通过基类名和作用域操作符(::)来限定。
二义性问题
当从不同的基类继承了同名成员,但是在派生类中没有定义同名成员,那么通过派生类对象名.成员名或者引用名.成员名或者派生类指针->成员名来访问成员就会存在二义性问题。解决措施是:使用类名限定。
虚基类
当派生类从多个基类派生,而这些基类又有共同基类,那么这个派生类中就会存在多个相同的成员,在访问派生类的成员时就会产生冗余,这些冗余的存在不仅仅是占用了空间,并且很可能会导致不一致性。虚基类的存在就是为了解决这个问题。
虚基类的声明:class B1:virtual public B。声明了虚基类后,多继承情况下就不会发生对同一基类继承多次而产生的二义性问题,并且为最远的派生类提供唯一的基类成员,而不产生多次复制。需要注意的是:在第一级继承时就需要将共同基类设计为虚基类。
虚基类及其派生类构造函数
标签:font 影响 style 绑定 通过 过程 mes 类的声明 一个
原文地址:https://www.cnblogs.com/puheng/p/9348364.html