1. c++继承的访问权限
c++中继承有三种:共有继承、保护继承、私有继承,三个关键字分别是:public、protected、private。每种继承的访问权限不一样,谈到继承的访问权限首先得清楚一个类中public、protected、private关键字修饰的属性和方法其对类创建出来的对象的访问权限。
-
[ 1]成员访问权限
#include<iostream> using namespace std; class A { public: int aPublic; void funPublic() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK funaPrivate(); }; protected: int aProtected; void funaProtected() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; private: int aPrivate; void funaPrivate() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; }; int main() { A a; a.aPublic; //OK, 类实例可以访问public成员 a.funPublic(); //OK, 类实例可以访问public方法 a.aProtected; //ON, 类实例可以不访问protect属性 a.funaProtected(); //NO, 类实例可以不访问protect方法 a.aPrivate; //NO, 类实例可以不访问private属性 a.funaPaPrivate(); //OK, 类实例可以不访问private方法 return 0; }
小结: 类的内部之间可以访问其属性和方法(不管是public、protected、private修饰即”同类无私有”)。类创建的实例,类的实例可以访问public属性和方法,不能访问protected和private属性和方法。
-
[ 2] 公有继承
#include<iostream> using namespace std; class A { public: int aPublic; void funPublicA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK funaPrivateA(); }; protected: int aProtected; void funaProtectedA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; private: int aPrivate; void funaPrivateA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; }; class B:public A { public: int bPublic; void funPublicB() { int b1 = aPublic; //OK int b2 = aProtected; //OK //int b3 = aPrivate; //NO //funaPrivate(); //NO }; protected: int bProtected; void funaProtectedB() { int b1 = aPublic; //OK int b2 = aProtected; //OK //int b3 = aPrivate; //NO }; private: int bPrivate; void funaPrivateB() { int a1 = aPublic; //OK int a2 = aProtected; //OK //int a3 = bPrivate; //NO }; }; int main() { B b; b.aPublic; //OK b.funPublicA(); //OK //b.aProtected; //NO //b.funaProtectedA(); //NO //b.aPrivate; //NO //b.funaPrivateA(); //NO return 0; }
小结:子类通过public继承,基类的各种权限不变 。子类创建的实例依然可访问父类的公有属性和方法,无法访问protected、private修饰的属性和方法。子类的内部可以访问父类的public、protected修饰的属性和方法。
-
[3 ] 保护继承
#include
using namespace std;class A { public: int aPublic; void funPublicA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK funaPrivateA(); }; protected: int aProtected; void funaProtectedA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; private: int aPrivate; void funaPrivateA() { int a1 = aPublic; //OK int a2 = aProtected; //OK int a3 = aPrivate; //OK }; }; class B:protected A { public: int bPublic; void funPublicB() { int b1 = aPublic; //OK int b2 = aProtected; //OK //int b3 = aPrivate; //NO //funaPrivate(); //NO }; protected: int bProtected; void funaProtectedB() { int b1 = aPublic; //OK int b2 = aProtected; //OK //int b3 = aPrivate; //NO }; private: int bPrivate; void funaPrivateB() { int a1 = aPublic; //OK int a2 = aProtected; //OK //int a3 = bPrivate; //NO }; }; int main() { B b; //b.aPublic; //NO //b.funPublicA(); //NO //b.aProtected; //NO //b.funaProtectedA(); //NO //b.aPrivate; //NO //b.funaPrivateA(); //NO return 0; }
小结:子类通过protected继承,父类的public降为protected属性,其他不变 。子类创建的实例不在能够访问父类的公有属性和方法,也无法访问protected、private修饰的属性和方法。子类的内部可以访问父类的public、protected修饰的属性和方法。
-
[ 4] 私有继承
子类通过private继承,父类的所有属性和方法的权限变成了private。同公有继承一样,子类创建的实例不能访问父类的任何成员和方法。子类的内部可以访问父类的public、protected修饰的属性和方法。如果后面又有C子类继承B类的话,那么C类的内部都将不再能够访问A类的属性和方法,但是是保护继承的话C的内部是可以访问A的属性和方法的。
2.多继承和虚继承
一个类有多个直接基类的继承关系称为多继承
#include<iostream>
using namespace std;
class A
{
public:
int m;
int a[9];
};
class B: public A
{
};
class C: public A
{
};
class D: public B, public C
{
};
int main()
{
cout << "A所占字节的大小:" << sizeof(A) << endl;
cout << "B所占字节的大小:" << sizeof(B) << endl;
cout << "C所占字节的大小:" << sizeof(C) << endl;
cout << "D所占字节的大小:" << sizeof(D) << endl;
D d;
//d.m = 10; //NO 存在二义性,编译器不知道m是属于A还是B
d.B::m = 10; //OK
d.C::m = 10; //OK
return 0;
}
如果一个子类继承了多个父类,而这些父类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性,并且在子类中进行多分拷贝,浪费存储空间。
程序编译结果如下:
为解决多继承中存在的二义性问题,c++提供了虚继承
虚继承可以解决多种继承的二义性及浪费存储空间的问题,那么B,C,D为什么所占的字节大小是44,44,48呢?
虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
详细可以看:
https://blog.youkuaiyun.com/bxw1992/article/details/77726390