c++(5·访问修饰符、重写隐藏重载、友元)
成员访问修饰符
作用
控制着类成员的访问 == 调用权限
分类:
- public公共:在类内,类外(类定义外),派生类,友元,都可以访问,通常存放对外公开的接口
- protected受保护:在类内,派生类,友元可以访问,通常存放在继承体系中可以访问的部分
- private私有:只能在类内,友元,可以访问,通常存放对类外隐藏实现的部分
访问修饰符和继承:
注意:访问修饰符并不会影响派生类是否可以 继承/隐藏/重写(即使是private的),只是影响是否能被访问
继承 vs. 重写 vs. 隐藏 vs. 重载
区别:
- 继承:
- 派生类没有重新定义基类方法,不包含任何/仅声明
- 对于构造,析构……特殊的成员,并不会继承,而是会生成默认的函数
- 如果基类的析构函数是虚析构函数,那么派生类的析构函数也会自动成为虚析构函数
- 重写/覆盖:
- 不同作用域,
- 基类的virtual,
- 派生类 同名,同返回类型,同形参列表
- 支持多态
- 隐藏:
- 不同作用域,
- 基类没有virtual,
- 派生类 同名,其中返回类型,形参列表 可以不同,可以隐藏掉基类所有同名函数
- 不支持多态
- 重载:
- 相同作用域,
- 同名,参数列表不同,返回类型可以相同也可以不同
覆盖 vs. 隐藏 的字面意思
- 重写/覆盖:强调拷贝再重写,因为都没有被遮住,可以在任意时刻选择任意版本的
- 隐藏:强调遮蔽再重写,如果选择基类,就只能查看基类部分,因为派生类被遮住
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Base {
public:
void func() {}
void func1() {}
void func1(float x) {}
private:
void func(int x) {}
void func1(int x) {}
virtual void func2() {}
};
class Derived : public Base {
public:
void func1() {}
void func2() {}
};
展开
上述流程:
- func:
- base中定义了2个重载版本,都会被Derived继承,
- 由于第2个版本为private,因此不能被derived调用
- func1:
- base中定义了3个重载版本,都会被Derived隐藏,
- 当在derived内直接调用func1时只能调用derived中的func1版本,但可以Base::func1 (作用域解析运算符)显式调用基类中的版本,
- base private的部分不能被外部调用,但是base public部分可以被外部调用,derived部分可以被外部调用
- func2:
- base中定义了1个版本,会被Derived重写,
- 外部代码不能通过基类指针/引用直接调用 private virtual 方法,即使实际类型是派生类对象,且在派生类中修改权限为private(可以用于“不想对外暴露 virtual 函数,而提供一个 public 的非虚函数给外界访问”的情形)
- 如果想要在外面调用,基类以及派生类必须都为public的
- 如果仅想调用派生类public virtual func2的,则需要创建派生类对象调用
继承访问修饰符
作用
控制派生类对象对基类成员的访问权限
分类
private部分由于没有访问权限所以我们直接忽略
- public 继承:基类的 public 和 protected 成员在派生类中保持原有访问权限
- protected 继承:基类的 public 和 protected 成员在派生类中变为protected
- private 继承(默认):基类的 public 和 protected 成员在派生类中变为private
友元
作用:
通过friend声明为友元,允许某个外部函数/类访问当前类的 private 和 protected 成员
分类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Box {
public:
Box(int w) : width(w) {}
// 声明友元函数
friend void printWidth(Box box);
// 声明友元类
friend class Printer;
private:
int width;
};
void printWidth(Box box) {
cout << "Box width: " << box.width << endl;
}
class Printer {
public:
void printWidth(Box box) {
cout << "Box width: " << box.width << endl;
}
};
展开
- 友元函数:
- 友元类:
特点:
- 友元关系是单向的,如果 A 是 B 的友元,B 是 C 的友元,A 不会自动成为 C 的友元
- 不能继承,基类的友元不是派生类的友元
- 不受访问修饰符影响,friend 声明可以放在 public、protected 或 private 区域,不影响其友元的性质
本文由作者按照 CC BY 4.0 进行授权