封装
数据封装 是面向对象编程的一个重要特点,用于防止函数直接访问类对象的内部成员。类成员的访问限制是通过类内关键字 public、private、protected 指定标记区域,称为 访问修饰符。
- 一个类可以有多个 public、protected 或 private 标记区域。
- 每个标记区域在下一个标记区域开始之前或者在遇到类主体结束右括号之前都是有效的。
- 类中未指定成员的
默认访问修饰符是 private
,而结构体中默认为 public
class ClassName
{
public:
// 公有成员
// 在类内、类外、派生类中都可被访问
protected:
// 受保护成员:为了与派生类共享,但又不想公开
// 在类内、派生类中可被访问,类外不允许
private:
// 私有成员,默认修饰
// 只允许类内访问,以及友元访问
};
继承
面向对象程序设计中最重要的一个概念是继承,允许依据一个基类来定义一个派生类,以此实现重用代码功能并提高执行时间。继承表示了 is a
关系,如狗是哺乳动物,因此狗具有哺乳动物的共性。一个类也可以继承/派生自多个类。继承方式同样有 public、protected、private,实际表现为 接口窄化。
class A :
public Base
{
};
class A :
protected Base
{
};
class A :
private Base
{
};
class A:
public Base_1, protected Base_2, private Base_3
{
};
一个派生类继承了所有的基类方法,但下列情况 除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数
访问权限
- 所有成员在 类内 都可以被访问;
- 派生类无法继承private成员(不可见),其他继承得到的成员在派生类的 内部 都可被访问,在派生类外部取决于继承方式和基类的成员属性;
- public 成员在类内、类外、派生类中都可被访问;
- protected 成员是为了与派生类共享,但又不想公开。因此在类内、派生类中可被访问,类外不允许;
- private 成员,是默认修饰,只允许类内访问,以及友元访问,在派生类中不可见(类内类外都不可访问)
接口窄化的具体说明:
- public 继承不改变public段和protected段
- protected 继承窄化public段,protected段不改变
- private 继承窄化public段和protected段
私有继承的含义: 为了接口与实现相分离,private 继承是对接口类的具体实现。
友元
C++严格控制了类中成员的访问权限,在类外只允许访问public成员。但有些情况下,需要允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,例如被重载的输入或输出操作符,经常需要访问类的私有数据成员。这就需要为该类构造“友元”。
一个类在定义时,声明 某函数 / 某类 / 某成员函数 是其友元 friend,给予对方所有的访问权限,包括私有(private)成员和保护(protected)成员。因此其友元函数/友元类能访问该类的所有类型的成员。
class X // 友元成员函数所属的类必须提前定义
{
public:
X(char);
~X();
char* foo(int);
};
class Base
{
int data; // 私有成员
// 非成员函数的运算符 operator<< 将拥有对 Y 的私有成员的访问权
friend std::ostream& operator<<(std::ostream& out, const Y& o);
friend char* X::foo(int); // 其他类的成员亦可为友元
friend X::X(char), X::~X(); // 其他类的构造函数与析构函数也可为友元
friend class Y; // 友元类声明
};
// 此 operator<< 仍需定义,作为非成员
std::ostream& operator<<(std::ostream& out, const Base& base)
{
return out << base.data; // 可访问私有成员 Y::data
}
- 友元声明,也是声明,可以替代预先的函数声明、类声明等,但声明友元成员函数时必须已经定义了其归属类。
- 友元关系不能被继承;
- 友元关系是单向的,不具有交换性。若类 B 是类 A 的友元,类 A 不一定是类 B 的友元,要看在类中是否有相应的声明;
- 友元关系不具有传递性。若类 B 是类 A 的友元,类 C 是 B 的友元,类 C 不一定是类 A 的友元,同样要看类中是否有相应的申明;
- 友元函数并不是类的成员函数,因此在类外定义友元函数时不能加上
class::ClassName
;