二、封装、继承与操作符重载
1、C++三种访问权限
1.1 访问限定符
public:公有的
protected:受保护的
private:私有的
1.2 访问权限
访问权限就是控制是否可以访问;类的实例是对象。
public:两个字(自由),类内、子类、友元可访问,类外对象也可访问;
protected:两个字(受限),类内、子类、友元可访问,但类外对象不可访问;
private:两个字(自闭),类内、友元可访问,但子类、类外对象不可访问。
| 访问权限/访问情况 | 类内 | 子类 | 友元 | 类外 |
|---|---|---|---|---|
| public | Y | Y | Y | Y |
| protected | Y | Y | Y | N |
| private | Y | N | Y | N |
1.2.1 什么是友元?
友元(friend),可以使得其他类中的成员函数以及全局范围内的函数访问当前类的 private 成员。
关于友元,有两点需要说明:
- 友元的关系是单向的。如果声明了 B 是 A 的友元类,不等于 A 是 B 的友元类,A 中的成员函数不能访问 B 中的 private 成员。
- 友元的关系不能传递。如果 B 是 A 的友元类,C 是 B 的友元类,不等于 C 是 A 的友元类。
除非有必要,一般不建议把整个类声明为友元类,而只将某些成员函数声明为友元函数,这样更安全一些。
友元破坏了面向对象的封装特性。
1.3 例子
创建基类、子类、友元(类、非成员函数、成员函数)、类外实例对象。
- 基类 Person
- 子类 Student
- 友元类 AddressA
- 友元函数
- Person 成员函数 做 AddressB 的友元函数
- 非成员函数 Show
/*
1、基类 Person
2、public 继承的 子类 Student
3、友元类 AddressA
4、友元函数
Person 成员函数 做 AddressB 的友元函数
非成员函数 Show
*/
#include<iostream>
using namespace std;
// 前向声明 方便 Person内的成员函数 做 其友元函数
class AddressB;
// 基类
class Person
{
// 友元类
friend class AddressA;
// 友元函数(非成员函数)
friend void Show(Person* person);
public:
Person(){}
Person(string Name, string NickName,int age, double salary)
{
this->age = age;
this->Name = Name;
this->NickName = NickName;
this->salary = salary;
}
// 类内 public、protected、private 都可以访问
// 友元函数(成员函数)
void showAddress(AddressB* address);
string NickName;
protected:
string Name;
int age;
private:
double salary;
};
// 友元函数(非成员函数)
void Show(Person* person)
{
cout << " 友元函数(非成员函数)" << endl;
cout << "public NickName: " << person->NickName << endl;
cout << "protected Name: " << person->Name << endl;
cout << "protected age: " << person->age << endl;
cout << "private salary: " << person->salary << endl;
}
// 友元函数(成员函数)
class AddressB
{
friend void Person::showAddress(AddressB* address);
public:
AddressB(string address) : address(address) {}
private:
string address;
};
void Person::showAddress(AddressB* address)
{
cout << " 友元函数(成员函数)" << endl;
cout << "private address: " << address->address << endl;
}
// 子类
class Student : public Person
{
public:
Student(string Name, string NickName,int age, double scores)
{
this->age = age;
this->Name = Name;
this->NickName = NickName;
// this->salary = salary; 子类 private 不能访问
this->scores = scores;
}
void ShowInformation()
{
cout << "public NickName: " << NickName << endl;
cout << "protected Name: " << Name << endl;
cout << "protected age: " << age << endl;
cout << "private salary: " << "子类 private 不能访问" << endl;
cout << "self private scores: " << scores << endl;
}
private:
double scores;
};
// 友元类
class AddressA
{
public:
void assessFriendAttributes(Person* person)
{
// 友元 都可以访问
cout << "public NickName: " << person->NickName << endl; // public
cout << "private salary: " << person->salary << endl; // private
cout << "protected age: " << person->age << endl; // protected
}
};
int main()
{
// 类外对象
Person* p1 = new Person(
"OldSea",
"YoungSea",
22,
100.5
);
cout << "------------------- 类外 public 访问 ----------------------" << endl;
cout << "public NickName: " << p1->NickName << endl;
cout << "------------------- 类外 public 访问 ----------------------" << endl;
cout << endl;
cout << "------------------- 类外 protected 访问 ----------------------" << endl;
cout << "类外 protected 无法访问" << endl;
// cout << p1->Name << endl; 类外 protected 无法访问
cout << "------------------- 类外 protected 访问 ----------------------" << endl;
cout << endl;
cout << "------------------- 类外 private 访问 ----------------------" << endl;
cout << " 类外 private 无法访问" << endl;
// cout << p1->salary << endl; 类外 private 无法访问
cout << "------------------- 类外 private 访问 ----------------------" << endl;
cout << endl;
AddressA* a1 = new AddressA();
cout << "------------------- 友元类 访问 ----------------------" << endl;
a1->assessFriendAttributes(p1);
cout << "------------------- 友元类 访问 ----------------------" << endl;
cout << endl;
AddressB* a2 = new AddressB("BeiJing");
cout << "------------------- 友元函数 访问 ----------------------" << endl;
Show(p1);
p1->showAddress(a2);
cout << "------------------- 友元函数 访问 ----------------------" << endl;
cout << endl;
Student* s1 = new Student(
"OldApple",
"YoungApple",
20,
88.5
);
cout << "-------------------- 子类 访问 ---------------------" << endl;
s1->ShowInformation();
cout << "-------------------- 子类 访问 ---------------------" << endl;
cout << endl;
return 0;
}
结果分析
1. Person 的类外对象 p1

类外对象可访问:public。
2. Person 的子类 Student s1

子类可访问:public、protected、类自身所有属性。
3. Person 的友元类 AddressA a1

友元类可访问:所有属性。
4. 友元函数

非成员函数 Show 做 Person 的 友元函数
Person 的成员函数 showAddress 做 AddressB 的 友元函数
友元函数可访问:所有属性。
2. struct 和 class 的访问权限
2.1 回忆一下 C 和 C++ 区别
- 成员
- C 中的 struct 只有数据,没有函数;
- C++ 中的 struct 有函数和数据,且有构造函数、访问权限。
- 访问权限
- C++ 中 struct访问权限也是 private、protected、public 三种;
- 默认的访问权限是 public。
- 是否可以继承
- C 中 struct 不存在继承的关系;
- C++ 中 struct 可以继承 class 和 struct,也可以被 class 和 struct 继承。
2.2 C++ struct与class的区别
- 默认的访问权限不同
- struct 默认的访问权限是 public,class 默认的访问权限是 private。
- 默认的继承访问权限不同
- struct 是 public,class 是 private。
- 默认的继承访问权限是取决于子类,而不取决于基类。即 struct 做子类,默认 public; class 做子类,默认 private。
定义模板参数
- class关键字可以用于定义模板参数,而 struct 不能。
3. 继承下的访问权限
子类继承的时候也需要指定访问权限,来规定访问的基类属性。
下表给出不同继承方式的属性访问权限变化:
| 基类访问权限/继承方式 | public 继承 | protected 继承 | private 继承 |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | N | N | N |


浙公网安备 33010602011771号