C++类是用户自定义的抽象数据类型,其在声明期间不分配内存,只有当这个类实例化后才分配内存。通过继承,子类不仅可以拥有新的属性和方法,还拥有父类的所有属性和方法。C++类继承的方式分为公有继承(public)、保护继承(protected)和私有继承(private),根据继承方式的不同,实现对子类和父类成员变量和方法的访问控制。当采用不同的继承方式后父类原来的变量在子类中的访问性如表格所示:
父类成员属性 子类继承 方式 |
Public |
Protected |
Private |
Public | Public | Protected | - |
Protected | Protected | Protected | - |
Private | Private | Private | - |
总结:
Public修饰的成员变量、方法,在类的内部、类的外部都能使用
Protected修饰的成员变量、方法在类的内部使用,在继承的子类的中可用
Private修饰的成员变量、方法只能在类的内部使用,不能在类的外部使用
继承的内存分配:
对于派生类B,其内存中首先给继承自父类的数据成员分配内存,其次是自己的数据成员。
类型的兼容性原则
指在任何需要基类对象的地方都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员
所指的兼容性规则中所指的替代包括以下情况:
子类对象可以当做父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
类继承中的构造函数和析构函数调用顺序:
利用子类声明一个子类对象时,构造函数和析构函数的调用顺序如下:
父类Constructor→子类Constructor
子类Deconstructor→父类Deconstructor
构造函数参数初始化列表:
构造函数的执行阶段可以分为初始化阶段和计算阶段,初始化阶段先于计算阶段执行,计算阶段及执行构造函数的函数体部分。
对于普通内置类型的初始化在哪个阶段执行没什么差别,但是以下三种情况必须使用初始化列表:
1、类的成员变量是对象的时候,通过初始化列表显式调用该对象(父类)的有参构造函数初始化该类的私有成员;
2、需要初始化const修饰的成员变量;
3、需要初始化引用成员变量。
参数列表的初始化顺序与数据成员在类中的声明顺序有关,而与初始化列表中的顺序无关。
在类中声明父类对象的混合情况下构造函数调用顺序:
1、根据继承顺序依次调用父类和子类的构造函数;
2、调用初始化列表中的显式调用的构造函数。
【一个例子】
#include <iostream>
#include <stdlib.h>
using namespace std;
class Object
{
public:
Object(int _a)
{
a = _a;
cout << "Object Constructor..." << a << endl;
}
~Object()
{
cout << "Object DeConstructor..." << endl;
}
private:
int a;
};
class Parent:public Object
{
public:
Parent(int _b,int _c):Object(_b)
{
b = _b;
c = _c;
cout << "Parent Constructor..." << b<<" "<<c<< endl;
}
~Parent()
{
cout << "Parent DeConstructor..." << endl;
}
protected:
private:
int b;
int c;
};
class Child: public Parent
{
public:
Child(int _d):Parent(_d*4,_d*2),a(_d),d(_d),obj(d*3),obj2(d*5)
{
cout << "Child Constructor..."<<d << endl;
}
~Child()
{
cout << "Child DeConstructor..." << endl;
}
private:
const int a;
int d;
Object obj;
Object obj2;
};
void playmain()
{
Child c1(1);
}
int main()
{
playmain();
system("pause");
return 0;
}
运行结果如下:
类继承中同名变量和同名函数调用规则:
利用子类对象调用同名变量和同名成员函数时,默认情况下调用子类的变量和函数,当要调用父类的变量和函数时,利用域作用符(::)显式调用
A 继承于B ,A、B都有函数print()
B b1;
b1.A::Print();