1 继承与派生
//情况一:
//类B拥有类A的成员变量,B has A,类B 依赖于 类A
class B{
public:
void funcB(){
}
A a;
};
//情况二:
//类C 的成员方法 需要类A的形参, C use A,类C 依赖于 类A
class C{
public:
void funC(A *a){
}
}
//情况三:
//D继承于A 类D 如果是继承类A 类D is A。类D继承于A 耦合度很高
class D:public A{
public:
void funD(){
}
}
派生与继承,是同一种意义两种称谓。继承是类之间定义的一种重要关系。
2 内存布局
父类和子类的内存布局,两者在内存空间上没有任何关系,是相对独立的。
子类继承自父类,会将父类已有的内存拷贝一份,放在一块新的内存空间,然后增加新的内容。
3 访问权限
class Parent{
public:
int pub;//类的 内部 和 外部 都能访问
protected:
int pro;//类的 内部 可以访问,类的外部不可以访问
private:
int pri;//类的 内部 可以访问,类的外部不可以访问
}
//公有继承
class Child:public Parent{
public:
void func(){
cout<<pub<<endl;
}
}
上面两处的public含义不同,一个是访问权限,一个是继承方式。
子类成员的标识和访问:
规则:
- 只要是父类中的private成员,不管是什么继承方式,子类都访问不了;
- 如果是公有继承,子类中的访问控制权限保持不变。
- 如果是保护继承,子类中父亲除了private成员,其余在子类中都是protected。
- 如果是私有继承,子类中的父亲除了private成员,其余在子类中都是private成员。
一个派生类继承了所有的基类方法,但下列情况除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
4 类的兼容性赋值原则
- 子类对象可以当作父类对象使用;
- 子类对象可以直接赋值给父类对象;
- 子类对象可以直接初始化父类对象;
- 父类指针可以直接指向子类对象;
- 父类引用可以直接引用子类对象。
Parent p;
Child c=p;
//由于c的内存空间大于等于p,所以p对象填充不满c对象空间
Child c;
Parent p=c;
//c对象所占用的内存空间>=p对象所占空间,能够填充满c对象空间
5 子类的析构和构造
在调用子类的构造函数时,一定会调用父类的构造函数;
父类先构造,子类后构造;
父类和子类的成员重名时,通过作用域来指明成员变量。
6 继承中的static
class A{
public:
static int a;
}
int A::a=100;//静态成员变量初始化
子类可以继承父类的static变量
7 多继承和虚继承
上面沙发床
继承自床类
和沙发类
,两者都有材质m
,但是在使用沙发床
时不知道使用哪个材质m
?
将父亲类继承爷爷类,改成虚继承(virtual),防止儿子在多继承父类时,出现爷爷中 的变量会拷贝多份。如果觉得后面不会出现拷贝多份的情况,可以不加virtural(虚继承)。
class Bed:virtual public Furniture{//虚继承
public:
void sleep(){
cout<<"在床上睡觉"<<endl;
}
}
多继承(环状继承),A->D, B->D, C->(A,B),需要使用虚继承:
格式:class 类名: virtual 继承方式 父类名
class D{......};
class B: virtual public D{......};
class A: virtual public D{......};
class C: public B, public A{.....};
虚继承–(在创建对象的时候会创建一个虚表)在创建父类对象的时候
A:virtual public D
B:virtual public D
参考:C++继承