继承
继承允许我们一句另一个类来定义一个类,这使得继承和维护一个程序变得更加容易,也达到了重用代码功能和提高执行效率的效果。
一般格式为:
class 派生类名 :访问修饰符 基类名{};
其中访问修饰符是public protected private
中的一个,默认为private
派生类可以访问基类中所有的非私有成员,因此基类成员如果不想被派生类的成员访问,则应该在基类声明为private
一个派生类继承了所有的基类非私有方法,但是下列情况除外:
- 基类的构造函数,析构函数和拷贝构造函数
- 基类的重载运算符
- 基类的友元函数
继承类型
- 公有继承:基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护乘员胡安,基类的私有成员不能直接被派生类访问,但是可以通过基类的公有和保护方法来访问。
- 保护继承:基类的公有和保护成员将成为派生类的保护成员
- 私有继承:公有和保护成员将称为派生类的私有成员
多继承
一个子类可以有多个父类,继承了多个父类的特性,不同父类用逗号隔开。
class <派生类名>:<继承方式><基类名>,<继承方式>,<基类名><继承方式><基类名>,..
{};
虚继承
因为C++多继承的特性,当从两个方向继承到同一个类的时候就可能会出现拷贝了两份相同数据的问题,这个时候访问被拷贝多份的数据成员如果没有加名字空间编译器就会报错,因为不确定到底访问的是哪一份变量。为了解决这个问题,我们要使用虚继承从而实现只拷贝一份变量。需要注意的一点是,虚继承是指对多个类继承一个类的时候需要进行虚继承,这样就能解决一个类继承这多个类的时候出现的成员重复。
具体见样例:
class A{};
class B:virtual public A{};
class C:virtual public A{};
class D:public B,public C{};//注意对D来讲用virtual已经晚了,我们在上面个多个类继承A的时候用虚继承,这样有其他类继承B,C等的时候就不会出现问题。
继承机理
编译器先通过基类的构造函数创建一个基类的对象,然后再通过派生类的构造函数在后面加上派生类的成员,并进行初始化。基类中私有成员对派生类不可见,但是派生类对象可以通过父类提供的接口对父类中的对象进行访问。实际上派生类成员是含有基类中的所有的成员的。
对于相同名字的数据成员,通过基类方法改变的是基类的数据成员,通过派生类方法改变的是派生类数据成员。如果想要访问基类的(公有)成员可以使用名字空间。
可以由以下测试看出:
#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:int b;
};
class B :public A
{//int c[50];int d;
};int main()
{B a;printf("%d", sizeof(a));return 0;
}
运行结果:
显然派生类中含有基类的私有成员,只是不可以直接访问。
派生类的构造函数
详见另一篇文章:构造函数,作者讲的很好。
在每次派生类构造函数调用时,首先会调用父类的构造函数,然后再调用派生类的构造函数,最后先调用派生类的析构函数,最后调用父类的析构函数。
在每个派生类构造函数中,如果我们要使用父类的有参构造函数,则需要在函数头部调用。如果我们没有显式地调用父类的构造函数则编译器会自动在派生类构造函数开头调用基类的无参构造函数。(如果基类只有有参构造函数编译器会因为找不到无参构造函数而报错)。
显式调用的格式如下:
class A
{public:A(int x){}
};
class B:public A
{
public:
B():A(x)//只可以在这一个地方显式调用
{}
};
在其他地方显式调用都是没有意义的。(相当于创建了一个没有办法引用的父类)
见下例:
#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:A(){printf("调用了无参构造函数\n");}~A(){printf("调用了析构函数\n");}A(int x){printf("调用了有参构造函数\n");a[0] = x;}int b;
};
class B :public A
{//int c[50];int d;
public:B(){A(5);printf("test\n");d = 0;}void Print(){printf("Hello world!\n");}
};int main()
{B* a=new B();printf("%d\n", sizeof(a));a->Print();delete a;return 0;
}
运行结果: