• C++ 基础与深度分析 Chapter11 类与面向对象编程(结构体与对象聚合、成员函数、访问限定符与友元)


    结构体与对象聚合

    在这里插入图片描述
    结构体的声明与定义(注意定义后面要跟分号来表示结束)

    #include <iostream>
    #include <vector>
    using namespace std;
    
    // 定义一个结构体,x和y组合到一起
    struct Str{
        int x;
        int y;
    }; // 这个分号是必须的
    
    struct Str; // 结构体的声明,告诉编译器这是一个结构体。
    
    int main()
    {
        Str m_str;
        m_str.x = 3;
        cout << m_str.x << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    仅有声明的结构体是不完全类型( incomplete type )

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
    }; 
    
    struct Str1;
    
    int main()
    {
        Str m_str;
        Str1 m_str1; // 报错 variable has incomplete type 'Str1'
        // 仅有声明的结构体是不完全类型( incomplete type )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    结构体(以及类)的一处定义原则:翻译单元级别
    变量在不同的编译单元都可以有不同的定义。结构体和类都是翻译单元级别(文件)的一处定义。

    数据成员(数据域)的声明与初始化
    在这里插入图片描述
    ( C++11 )数据成员可以使用 decltype 来声明其类型,但不能使用 auto

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        decltype(3) x;
        // 这里不能使用auto
    }; 
    
    
    int main()
    {
        Str m_str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    数据成员声明时可以引入 const 、引用等限定

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        const int x = 5;
    }; 
    
    int main()
    {
        Str m_str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    数据成员会在构造类对象时定义
    在这里插入图片描述
    类内成员初始化( C++11 )

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        int x = 5; // 类内成员初始化
    }; 
    
    int main()
    {
        Str m_str;
        cout << m_str.x << endl; // 5
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    聚合初始化:从初始化列表到指派初始化器
    在这里插入图片描述
    在这里插入图片描述
    但是这里有个问题,就是这样的话,顺序一定要和Str里面变量声明的顺序相同,不然一定会出错。c++20使用了一个指派初始化器
    在这里插入图片描述
    在这里插入图片描述
    mutable 限定符

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        mutable int x = 0; // mutable 可修改的
        int y = 1;
    }; 
    
    int main()
    {
        const Str m_str;
        m_str.x = 3; // 这样x就是可修改的了
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    静态数据成员 多个对象之间共享的数据成员

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        int x = 0;
        int y = 1;
    }; 
    
    
    int main()
    {
        Str m_str1;
        Str m_str2;
        m_str1.x = 100;
        cout << m_str1.x << endl; // 100
        cout << m_str2.x << endl; // 0 m_str1和m_str2是2个不同的对象,分别包含一组x和y
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    但是如果我们把数据成员设置成静态成员,那么m_str1和m_str2的数据成员之间就可以共享了。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        static int x;
        int y = 1;
    }; 
    
    int Str::x;
    int main()
    {
        Str m_str1;
        Str m_str2;
        m_str1.x = 100;
        cout << m_str1.x << endl; // 100
        cout << m_str2.x << endl; // 100 x是静态成员,2个对象之间的值共享了
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    C++98 :类外定义, const 静态成员的类内初始化
    在这里插入图片描述
    C++17 :内联静态成员的初始化
    在这里插入图片描述
    可以使用 auto 推导类型:
    注意只有静态数据成员可以,一般的数据成员类型不支持auto。但是可以使用delctype。

    静态数据成员的访问:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        static int x;
    }; 
    
    int Str::x = 3;
    
    int main()
    {
        Str m_str1;
        Str* ptr = &m_str1;
        cout << Str::x << endl;  // 3 域操作符
        cout << m_str1.x << endl;  // 3
        cout << ptr->x << endl;  // 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在类的内部声明相同类型的静态数据成员:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    成员函数

    在这里插入图片描述

    基本概念

    由于引入了成员函数,就把简单的结构体(聚集数据),变成了抽象数据类型。就是类。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str{
        int x = 3;
    
        // 成员函数
        void fun()
        {
            cout << x << endl;
        }
    }; 
    
    void fun(Str obj)
    {
        cout << obj.x << endl;
    }
    
    int main()
    {
        Str m_str;
        // fun(m_str);
        m_str.fun();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    关键字 class,明确的表明是一个类

    class Str{
    public:
        int x = 3;
    
        // 成员函数
        void fun()
        {
            cout << x << endl;
        }
    }; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类本身形成域,称为类域。

    成员函数的声明与定义

    类内定义(隐式内联)

    #include <iostream>
    #include <vector>
    using namespace std;
    
    class Str{
    public:
        int x = 1;
    
        // 类内定义
        void fun()
        {
            cout << x << endl;
        }
    }; 
    
    int main()
    {
        Str m_str;
        m_str.x = 3;
        m_str.fun();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    为了防止多个文件引用过一个类的成员函数,会产生重复定义。所以成员函数要设计成隐式内联的。

    类内声明 + 类外定义
    在这里插入图片描述
    在这里插入图片描述
    类外定义的函数,函数不是内联的。

    在这里插入图片描述
    类与编译期的两遍处理
    在这里插入图片描述
    成员函数与尾随返回类型( trail returning type )
    在这里插入图片描述
    在这里插入图片描述

    成员函数与 this 指针

    #include <iostream>
    #include <vector>
    #include "header.h"
    using namespace std;
    
    int main()
    {
        Str m_str;
        m_str.x = 5;
        cout << &m_str << endl; // 0x7ffee13066e8
        m_str.fun(); // 0x7ffee13066e8,编译器会调用fun(&m_str)
    
        Str m_str2;
        m_str2.x = 10;
        cout << &m_str2 << endl; // 0x7ffee13066e0
        m_str2.fun(); // 0x7ffee13066e0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    #include <iostream>
    using namespace std;
    class Str{
    public:
        int x = 1;
    
        // 给fun一个隐藏的参数 Str* this,这个是Str第一个参数
        void fun()
        {
            cout << this << endl;
            cout << this->x << endl;
        }
    }; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以通过this来显式访问类的成员数据
    在这里插入图片描述
    this是一个Str * const的指针,它指向了Str的对象。this本身不可修改,但是this指向的内容可以修改。有时候我们不想类外部的结构修改类内部的数据成员或者成员函数.

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    成员函数的名称查找与隐藏关系

    在这里插入图片描述

    静态成员函数

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str
    {
        inline static int x; // 静态数据成员
        // 静态成员函数,不能在静态成员函数中使用成员函数x
        // fun会被共享,不会传入this。所以没法调用this->x
        // 为什么要引入静态成员函数
        // 一般描述和类紧密相关的东西,同时不需要对象具体信息获取相应的结果
        static void fun()
        {
            cout << x << endl;
        }
    };
    
    int main()
    {
        Str m_str1;
        m_str1.fun();
        Str::fun();
        Str m_str2;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述
    在这里插入图片描述
    成员函数基于引用限定符的重载( C++11 )
    在这里插入图片描述
    在这里插入图片描述

    访问限定符与友元

    在这里插入图片描述
    使用public/private/protected限定类成员的访问权限

    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct Str
    {
        void fun()
        {
            // private内部可以访问
            cout << x << endl;
        }
    // 私有的
    private:
    // protected,外面也无法访问
    // public:
        int x;
        int y;
    
    };
    
    int main()
    {
        Str m_str;
        // 如果x是public,就可以访问
        cout << m_str.x << endl; // error: 'x' is a private member of 'Str'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述
    在这里插入图片描述
    struct默认是public,class默认是private。
    在这里插入图片描述
    访问权限的引入使得可以对抽象数据进行封装。比如我们买的电视,就是封装了很多线路。外面只有几个接口。

    使用友元打破访问权限限制——关键字friend
    声明某个函数是friend友元

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main();
    
    class Str
    {
        // 通过friend告诉Str,main是Str的好朋友,可以访问它的private成员
        friend int main();
        inline static int x;
    };
    
    int main()
    {
        Str m_str;
        cout << Str::x << endl; // 将main设置为友元
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    也可以声明某个类是类的friend

    #include <iostream>
    #include <vector>
    using namespace std;
    
    class Str2;
    
    class Str
    {
        // Str2是Str的友元,Str2的函数可以访问Str的private成员
        friend Str2;
        inline static int x;
    };
    
    class Str2
    {
        void fun()
        {
            cout << Str::x << endl; 
        }
    };
    
    int main()
    {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    friend就是来打破封装的,但是要慎重使用friend。封装是很有用的,所以不要轻易的打破封装,会有风险。如果我们声明了friend,那么它就可以访问该类的所有成员,所有成员都暴露给这个朋友了。

    friend放到哪个section都可以,不论是private,public或者protect都可以。

    在这里插入图片描述
    友元类内声明:
    在这里插入图片描述
    使用限定名称并非友元类的声明。
    在这里插入图片描述
    在这里插入图片描述
    在类内无法定义友元类,只能是声明
    在这里插入图片描述
    在类外面定义友元函数,在类里面声明它。
    在这里插入图片描述
    在类的内部定义友元函数
    在这里插入图片描述
    隐藏友元:
    在这里插入图片描述

  • 相关阅读:
    HugeGraph Hubble 配置 https 协议的操作步骤
    前端作业(17)
    安防行业商业供应链系统:加速企业数字化升级,助推供应链平台一体化协同发展
    正则表达式
    ROS 2知识:通信协议 DDS/RTPS
    【知识图谱】概述
    省市县:数十万数据集PM2.5面板数据&柵格数据(1998-2019)
    CLIP:多模态领域革命者
    华为机试练习题:HJ51 输出单向链表中倒数第k个结点
    断点测试怎么做?一文教你用Charles 工具做好接口测试!
  • 原文地址:https://blog.csdn.net/weixin_43716712/article/details/125514846