二、封装、继承与操作符重载

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 例子

创建基类、子类、友元(类、非成员函数、成员函数)、类外实例对象

  1. 基类 Person
  2. 子类 Student
  3. 友元类 AddressA
  4. 友元函数
    • 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

image

类外对象可访问:public

2. Person 的子类 Student s1

image

子类可访问:publicprotected类自身所有属性

3. Person 的友元类 AddressA a1

image

友元类可访问:所有属性

4. 友元函数

image

非成员函数 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

画图理解,图像出处
image

所有记录:游戏开发:C++学习

posted @ 2024-04-14 23:52  bok_tech  阅读(13)  评论(0)    收藏  举报