类之间的关系:包含、使用、继承
class Parent
{
public:
void print()
{
cout << "a: " << a << "b: " << b << endl;
}
private:
int a;
int b;
};
//class Child : private Parent
//class Child : protected Parent
class Child : public Parent
{
private:
int c;
};
void main()
{
Child c1;
system("pause");
}
子类拥有父类的所有成员变量和成员函数;
子类可以拥有父类没有的方法和属性 ;
子类就是一种特殊的父类 ;
子类对象可以当作父类对象使用 ;
public继承:父类成员 在 子类 中保持原有访问级别;
private继承:父类成员 在 子类 中变成private成员;
protected继承:父类中 public 成员会变成 protected;父类中 protected 仍然是;private仍然是;
看调用语句,在子类的内部还是外部;
看子类如何从父类继承;
看父类中的访问级别;
子类就是特殊的父类 (base *p = &child);
父类 指针(引用)指向 子类对象:Parent *p = &chile;
子类指针做函数父类参数;printP(&chile);
子类引用做函数父类参数;printP(chile);
子类对象 初始化 父类对象;Parent p = chile;
类在C++编译器的内部可以理解成结构体,子类是由父类成员叠加子类新成员得到的;
objA: | objA.x | objA.y |
-->
objB: | objB.x | objB.y | objB.s |
-->
objC: | objC.x | objC.y | objC.s | objC.n | objC.m |
在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化;
在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理;
// 创建子类对象 --> 首先调用父类的构造函数 --> 再执行子类的构造函数
Child c1(1, 2, 3);
// 当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
Child(int a, int b, int c) : Parent(a, b);
// 析构函数调用的先后顺序与构造函数相反
先构造父类,再构造成员变量(组合对象变量)、最后构造自己;
先析构自己,在析构成员变量(组合对象变量)、最后析构父类
当子类成员变量与父类成员变量同名时,子类依旧从父类继承同名成员 ;
在子类中通过作用域分辨符::进行同名成员区分(在派生类中使用基类的同名成员,显式地使用类名限定符);
同名成员存储在内存中的不同位置 ;
基类定义的静态成员,将被所有派生类共享;
static 成员遵守派生类的访问控制;
子类访问静态成员:类名::成员; 对象名.成员
注意:
class Parent
{
public:
static int i;
}
int Parent::i = 100;
// 初始化静态成员,并为静态成员分配内存! 才能给子类使用
一个类有多个直接基类的继承关系称为多继承
class child : public Base1, public Base2
多继承二义性原因:
如果一个子类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
class B {public: int b;};
class B1 : public B {public: int b1;};
class B2 : public B {public: int b2;};
class C : public B1, public B2
{
public:
int c;
}
void test()
{
C c;
c.B; //err 无法判断B从哪里继承
}
多继承二义性解决:
// 虚继承 virtual
class B1 : virtual public B {public: int b1;};
class B2 : virtual public B {public: int b2;};
// 使用虚继承后,基类B的构造函数只调用了一次
//可以判断在子类C定义的对象,内存模型中B1、B2共有一份B。。。
原文:https://www.cnblogs.com/2dx3906/p/13173372.html