1. 访问权限总结
- 当存在继承时
- 子类成员函数:
- 可以访问父类的public和protected成员
- 不可访问父类的private成员
- 子类实例:
- public继承的子类实例可访问父类的public成员,不可访问private和protected成员
- protected与private继承的子类实例不可访问父类的任何成员
- 综上,子类实例访问父类成员,只有一种情况:public继承的子类访问父类中的public成员
- 子类成员函数:
画个表格更清晰:
实验代码如下:
#include <iostream>
using namespace std;
#define MEMBER_FUNCTIONS_FOR_PRINTING_ALL_KINDS_OF_MEMBERS \
public: \
void printBase() { \
cout << baseDataInPublic << endl; \
cout << baseDataInProtected << endl; \
\
protected_print_public_base(); \
protected_print_protected_base(); \
private_print_public_base(); \
private_print_protected_base(); \
\
A_public_print(); \
A_protected_print(); \
} \
\
protected: \
void protected_print_public_base() {cout << baseDataInPublic << endl; } \
void protected_print_protected_base() {cout << baseDataInProtected << endl; } \
\
private: \
void private_print_public_base() {cout << baseDataInPublic << endl; } \
void private_print_protected_base() {cout << baseDataInProtected << endl; }
class A
{
public:
A(int a, int b, int c) :
baseDataInPublic(a), baseDataInProtected(b), baseDataInPrivate(c) {}
public:
int baseDataInPublic;
void A_public_print() { cout << baseDataInPublic << endl; }
protected:
int baseDataInProtected;
void A_protected_print() { cout << baseDataInProtected << endl; }
private:
int baseDataInPrivate;
void A_private_print() { cout << baseDataInPrivate << endl; }
};
class B : public A
{
public:
B(int a, int b, int c) : A(a, b, c) {}
~B(){}
MEMBER_FUNCTIONS_FOR_PRINTING_ALL_KINDS_OF_MEMBERS
};
class C : protected A
{
public:
C(int a, int b, int c):A(a, b, c) {}
~C(){}
MEMBER_FUNCTIONS_FOR_PRINTING_ALL_KINDS_OF_MEMBERS
};
class D : private A
{
public:
D(int a, int b, int c):A(a, b, c){}
~D(){}
MEMBER_FUNCTIONS_FOR_PRINTING_ALL_KINDS_OF_MEMBERS
};
int main()
{
B *pb = new B(10, 20, 30);
C *pc = new C(10, 20, 30);
D *pd = new D(10, 20, 30);
cout << "Access member variable by member function...\n";
cout << "Public Herit: \n";
pb->printBase();
cout << "Protected Herit: \n";
pc->printBase();
cout << "Private Herit: \n";
pd->printBase();
// Only public heritage's Base class's public members can be accessed
cout << "Access members directly...\n";
cout << pb->baseDataInPublic << endl;
pb->A_public_print();
// pb->A_protected_print(); // Cannot access
// cout << pc->baseDataInPublic << endl; // Cannot access
// cout << pd->baseDataInPublic << endl; // Cannot access
return 0;
}
以上是访问权限总结。
2. 父类成员在子类中是什么类型
关于“父类成员在子类中是什么类型的成员”,可参见下表:
父类public成员 | 父类protected成员 | 父类private成员 | |
public继承 | 子类public成员 | 子类protected成员 | 不可见 |
protected继承 | 子类protected成员 | 子类protected成员 | 不可见 |
private继承(默认) | 子类private成员 | 子类private成员 | 不可见 |
对上表可做2点总结:
- 父类的private成员对任何继承方式的子类都是不可见的;
- 其他情况,总是依据“类的继承类型”和“该成员在父类中的类型”这二者选择更严格的一种来作为“父类成员在子类中的成员类型”。
3. Protected关键字的作用
那么,protected关键字有什么重要作用呢?
依据笔者个人的经验和理解,有2个作用:
1. 如果想一个类只能成为父类,而不想它有任何对象,则可以将其构造函数声明为protected的 (因为如果是public的,则可以有自己的对象;而如果是private的构造函数,则无法有子类,因为子类无法构造父类的部分。)
2. protected继承和private继承都能够使得多态不存在。
见如下代码:
class A {
public:
virtual void f() {}
};
class B : protected A
{};
int main()
{
A* pa = new B(); // 此句编译不通过
return 0;
}
因为B对于A来说是不可访问的父类。
这个特性在一些实现中还是很有用处的,主要就是可以避免误用多态。
最后,其实protected和private继承,大约主要还是用在库编程和模板编程中。有文章统计过一些热门的C++项目,极少用到private和protected继承,用了的也大多是和模板库相关的。不过作为知识结构的一部分,还是有必要有较深刻理解的。
[2022-01-09] 更新
(完)