C++_类和对象(中、下篇)—— const成员函数、取地址运算符的重载、深入构造函数、类型转换、static成员、友元

news2024/9/22 18:20:53

目录

三、类和对象(中)

6、取地址运算符重载

1、const成员函数

2、取地址运算符的重载 

四、类和对象(下)

1、深入构造函数

2、类型转换

3、static成员 

4、友元


三、类和对象(中)

6、取地址运算符重载

1、const成员函数

  1. 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面。
  2. const实际修饰该成员函数隐含的this指针指向的对象,表明在该成员函数中不能对类的任何成员进行修改。没有修改的话就可以加,修改的话就不可以加const。
  3. const 修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this
    #include<iostream>
    using namespace std;
    class Date
    {
    public:
        Date(int year = 1, int month = 1, int day = 1)
        {
            _year = year;
            _month = month;
            _day = day;
        }
    
        
        //若不加上const,则为void Print(Date* const this),this指针中的const修饰的是指针不能被改变
        // void Print(const Date* const this) const
        void Print() const
        {
            cout << _year << "-" << _month << "-" << _day << endl;
        }
    
    private:
        int _year;
        int _month;
        int _day;
    };
    
    int main()
    {
        // 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩
        Date d1(2024, 7, 5);
        //&d -> Date*
        d1.Print();
    
        const Date d2(2024, 8, 5);
        //&d -> const Date*
        d2.Print();
    
        return 0;
    }

总结:一个成员函数,不修改成员变量的建议都加上。 

c2821e9ff43843618ba4f742822423aa.png

更多详细例子可以去看博主的C++_类与对象(中篇)的日期类实现中的const修饰:C++_类和对象(中篇)—— 运算符重载、赋值运算符重载、日期类实现-CSDN博客

2、取地址运算符的重载 

  1. 取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载。
  2. ⼀般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。
  3. 除非⼀些很特殊的场景,比如我们不想让别人取到当前类对象的地址,就可以自己实现⼀份,胡乱返回⼀个地址。
class Date
{
public :
    Date* operator&()
    {
        return this;
        // return nullptr;
    }

    const Date* operator&()const
    {
        return this;
        // return nullptr;
    }

private :
    int _year ; // 年
    int _month ; // ⽉
    int _day ; // ⽇
};

四、类和对象(下)

1、深入构造函数

  1. 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有⼀种方式,就是初始化列表,初始化列表的使用方式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后面跟⼀个放在括号中的初始值或表达式。
  2. 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。
  3. 引⽤成员变量,const成员变量,没有默认构造的类类型成员变量,这三种变量必须放在初始化列表位置进⾏初始化,否则会编译报错。
    #include<iostream>
    using namespace std;
    
    class Time
    {
    public:
        Time(int hour)
            :_hour(hour)
        {
            cout << "Time()" << endl;
        }
    
    private:
        int _hour;
    };
    
    class Date
    {
    public:
        Date(int& x, int year = 1, int month = 1, int day = 1)
            :_year(year)
            ,_month(month)
            ,_day(day)
            ,_t(12)
            ,_ref(x)
            ,_n(1)
        {
            // error C2512: “Time”: 没有合适的默认构造函数可⽤
            // error C2530 : “Date::_ref” : 必须初始化引⽤
            // error C2789 : “Date::_n” : 必须初始化常量限定类型的对象
        }
    
        void Print() const
        {
            cout << _year << "-" << _month << "-" << _day << endl;
        }
    
    private:
        int _year;
        int _month;
        int _day;
        Time _t; // 没有默认构造
        int& _ref; // 引⽤
        const int _n; // const
    };
    
    int main()
    {
        int i = 0;
        Date d1(i);
        d1.Print();
    
        return 0;
    }
  4. C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。
  5. 尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。

    123dc7fdb22d4b3a8d179fb3b7c38b39.png

  6. 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持⼀致。
    #include<iostream>
    using namespace std;
    
    class Time
    {
    public:
        Time(int hour)
            :_hour(hour)
        {
            cout << "Time()" << endl;
        }
    
    private:
        int _hour;
    };
    
    class Date
    {
    public:
        Date()
            :_month(2)
        {
            cout << "Date()" << endl;
        }
    
        void Print() const
        {
            cout << _year << "-" << _month << "-" << _day << endl;
        }
    
    private:
        // 注意这⾥不是初始化,这⾥给的是缺省值,这个缺省值是给初始化列表的
        // 如果初始化列表没有显⽰初始化,默认就会⽤这个缺省值初始化
        int _year = 1;
        int _month = 1;
        int _day;
    
        Time _t = 1;
        const int _n = 1;
        int* _ptr = (int*)malloc(12);
    };
    
    int main()
    {
        Date d1;
        d1.Print();
    
        return 0;
    }

初始化列表总结:
  1. 无论是否显示写初始化列表,每个构造函数都有初始化列表;
  2. 无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化;

ccb5f5b9984240aea94d80a88842f929.png

思考:下面我们来看一道程序编程题目

2cca860b3e47446782287829644096b2.png c4badc7eae484b1794bcbe436dff7a1b.png

#include<iostream>
using namespace std;

class A
{
public:
    A(int a)
        :_a1(a)
        , _a2(_a1)
    {}

    void Print() 
    {
        cout << _a1 << " " << _a2 << endl;
    }

private:
    int _a2 = 2;
    int _a1 = 2;
};

int main()
{
    A aa(1);

    aa.Print();
}

2、类型转换

  1. C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
  2. 构造函数前面加explicit就不再支持隐式类型转换。
  3. 类类型的对象之间也可以隐式转换,需要相应的构造函数支持。
    #include<iostream>
    using namespace std;
    
    class A
    {
    public:
        // 构造函数explicit就不再⽀持隐式类型转换
        // explicit A(int a1)
        A(int a1)
                :_a1(a1)
        {}
    
        //explicit A(int a1, int a2)
        A(int a1, int a2)
                :_a1(a1)
                , _a2(a2)
        {}
    
        void Print()
        {
            cout << _a1 << " " << _a2 << endl;
        }
    
        int Get() const
        {
            return _a1 + _a2;
        }
    
    private:
        int _a1 = 1;
        int _a2 = 2;
    };
    
    class B
    {
    public:
        B(const A& a)
                :_b(a.Get())
        {}
    
    private:
        int _b = 0;
    };
    
    //内置类型->自定义类型的转换(隐式类型的转化)
    //自定义类型->自定义类型转换(使用构造函数)
    int main()
    {
        // 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3
        // 编译器遇到连续构造+拷⻉构造->优化为直接构造
        A aa1 = 1;
        aa1.Print();
    
        const A& aa2 = 1;
        //拷贝的值放在临时变量中,具有常性,需要用const修饰,才能通过编译
    
        // C++11之后才⽀持多参数转化
        A aa3 = { 2,2 };
    
        // aa3隐式类型转换为b对象
        // 原理跟上⾯类似
        B b = aa3;//正常来说是不可以的
        const B& rb = aa3;
        //拷贝的值放在临时变量中,具有常性,需要用const修饰,才能通过编译
    
        A aa3 = {1,1};
        const A& aa4 = {1,1};
        //这是调用多参数的形式,本质都是隐式类型的转化
    
        return 0;
    }

    7f22b55accf843e2a78c49581dc5dc30.png

3、static成员 

  1. 用static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进行初始化。
  2. 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。
  3. 用static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
  4. 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针。
  5. 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
  6. 突破类域就可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。
  7. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。
  8. 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表。
    // 实现⼀个类,计算程序中创建出了多少个类对象?
    #include<iostream>
    using namespace std;
    
    class A
    {
    public:
        A()
        {
            ++_scount;
        }
    
        A(const A& t)
        {
            ++_scount;
        }
    
        ~A()
        {
            --_scount;
        }
    
        static int GetACount()
        {
            return _scount;
        }
    
    private:
        // 类⾥⾯声明
        static int _scount;
    };
    
    // 类外⾯初始化
    int A::_scount = 0;
    
    int main()
    {
        cout << A::GetACount() << endl;
        A a1, a2;
        A a3(a1);
        cout << A::GetACount() << endl;
        cout << a1.GetACount() << endl;
    
        // 编译报错:error C2248: “A::_scount”: ⽆法访问 private 成员(在“A”类中声明)
        //cout << A::_scount << endl;
    
        return 0;
    }

    思考:求1+2+3+...+n_牛客题霸_牛客网

2e250edfe62348769b269433bf3c823a.png

        既然题目要求不能使用这些方法,即循环累加、递归、等差数列公式等思路也行不通,C++解题模式下中提供的解决方案:使用Sum类和Solution类来解决,如下:

ead2fe9c15a04e2db8d2cd826c952c8c.png

class Sum
{
public:
    Sum()
    {
        _ret += _i;
        ++_i;
    }

    static int GetRet()
    {
        return _ret;
    }

private:
    static int _i;
    static int _ret;
};

int Sum::_i = 1;
int Sum::_ret = 0;

class Solution 
{
public:
    int Sum_Solution(int n) 
    {
        // 变⻓数组
        Sum arr[n];//VS编译器不能通过
        //VS编译器可通过的写法:Sum* arr = new Sum[n];
        return Sum::GetRet();
    }
};
思考:
设已经有A,B,C,D 4个类的定义,程序中A,B,C,D构造函数调用顺序为?(选E)
设已经有A,B,C,D 4个类的定义,程序中A,B,C,D析构函数调用顺序为?(选B)
//以下为选项:
A:D B A C
B:B A D C
C:C D B A
D:A B D C
E:C A B D
F:C D A B


//题目具体代码:
class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    
    ~A()
    {
        cout << "~A()" <<enl;
    }
};

class B
{
public:
    B()
    {
        cout << "B()" << endl;
    }
    
    ~B()
    {
        cout << "~B()" <<enl;
    }
};

class C
{
public:
    C()
    {
        cout << "C()" << endl;
    }
    
    ~C()
    {
        cout << "~C()" <<enl;
    }
};

class D
{
public:
    D()
    {
        cout << "D()" << endl;
    }
    
    ~D()
    {
        cout << "~D()" <<enl;
    }
};

C c;

int main()
{
    A a;
    B b;
    static D d;
    //构造:局部的静态,只有第一次找到初始化,才能够调用
    //析构:先析构局部变量(后面的先析构),后析构全局变量。
    return 0;
}

思路要点:

  1. 构造:局部静态变量,只有第一次找到初始化,才能够调用。
  2. 析构:先析构局部变量(后面的先析构),后析构全局变量。

VS运行编译结果:

2bff78a635634705bd954862ed787160.png

4、友元

  1. 友元提供了⼀种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到⼀个类的里面。
  2. 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  4. ⼀个函数可以是多个类的友元函数。
  5. 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
  6. 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。
  7. 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。
  8. 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用(项目程序中希望是低耦合和高内聚)。
    #include<iostream>
    using namespace std;
    
    // 前置声明,都则A的友元函数声明编译器不认识B
    class B;
    
    class A
    {
        // 友元声明
        friend void func(const A& aa, const B& bb);
    
    private:
        int _a1 = 1;
        int _a2 = 2;
    };
    
    class B
    {
        // 友元声明
        friend void func(const A& aa, const B& bb);
    
    private:
        int _b1 = 3;
        int _b2 = 4;
    };
    
    void func(const A& aa, const B& bb)
    {
        cout << aa._a1 << endl;
        cout << bb._b1 << endl;
    }
    
    int main()
    {
        A aa;
        B bb;
        func(aa, bb);
    
        return 0;
    }
    #include<iostream>
    using namespace std;
    
    class A
    {
        // 友元声明
        friend class B;
    private:
        int _a1 = 1;
        int _a2 = 2;
    };
    
    class B
    {
    public:
        void func1(const A& aa)
        {
            cout << aa._a1 << endl;
            cout << _b1 << endl;
        }
    
        void func2(const A& aa)
        {
            cout << aa._a2 << endl;
            cout << _b2 << endl;
        }
    
    private:
        int _b1 = 3;
        int _b2 = 4;
    };
    
    int main()
    {
        A aa;
        B bb;
        bb.func1(aa);
        bb.func1(aa);
    
        return 0;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2144181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从数据仓库到数据中台再到数据飞轮:我了解的数据技术进化史

这里写目录标题 前言数据仓库&#xff1a;数据整合的起点数据中台&#xff1a;数据共享的桥梁数据飞轮&#xff1a;业务与数据的双向驱动结语 前言 在当今这个数据驱动的时代&#xff0c;企业发展离不开对数据的深度挖掘和高效利用。从最初的数据仓库&#xff0c;到后来的数据…

docker可视化管理工具推荐!docker.ui

正式介绍之前&#xff0c;可以看下这款工具的截图&#xff0c;开源地址在文末提供&#xff1a; docker.ui&#xff1a;一个可视化的docker管理工具 docker是一个开源的容器平台&#xff0c;可以让开发者和运维人员快速地构建、运行和部署应用。 docker的优势在于它可以实现应…

Cpp类和对象(上)(3)

文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言…

dcmtk在MWLSCP会忽略对于字符集的匹配

版本信息 dcmtk v3.6.4 2018-11-29 发现的原因 在我将dcmtk的wlmscpfs当作MWLSCP使用的时候&#xff0c;我在SCU端为了防止过来的数据中存在不识别的字符集&#xff0c;对于收到的数据数据进行了字符集的过滤&#xff0c;但是发现过滤没有生效。 确保数据源 首先需要确认数…

pywebview 中错误使用async

错误代码 正确示例 完整代码 前端代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>pywebview …

哈希表数据结构学习

哈希表数据结构学习 哈希表基本概念哈希方法单值哈希与多值哈希哈希冲突1. 开放寻址法&#xff08;Open Addressing&#xff09;2. 链地址法&#xff08;Chaining&#xff09;3. 再哈希法&#xff08;Rehashing&#xff09;4. 建立公共溢出区&#xff08;Overflow Area&#xf…

OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(下)

往期知识点记录&#xff1a; OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——轻量系统STM32F407芯片移植案例 OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——Combo解决方案之W800芯片移植案例 OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——小型系统STM32M…

『功能项目』窗口可拖拽脚本【59】

本章项目成果展示 我们打开上一篇58第三职业弓弩的平A的项目&#xff0c; 本章要做的事情是给坐骑界面挂载一个脚本让其显示出来的时候可以进行拖拽 创建脚本&#xff1a;DraggableWindow.cs using UnityEngine; using UnityEngine.EventSystems; public class DraggableWindo…

使用three.js+vue3完成无人机上下运动

效果图如上 代码&#xff1a; <template><div class"drones"><div ref"dronesContainer" class"drones-container"></div></div></template><script setup>import { ref, onMounted, onUnmounted, …

性能再升级,华为Mate 70 Pro曝光,设计新颖且配置遥遥领先

在智能手机市场竞争日益激烈的今天&#xff0c;各大厂商都在努力提升自家产品的性能和设计。 华为作为中国领先的手机品牌&#xff0c;一直备受关注。 近日&#xff0c;有关华为Mate 70 Pro的曝光信息引发了广泛关注&#xff0c;据悉&#xff0c;这款新机将在性能、设计和配置…

vue和thinkphp路由伪静态配置

vue路由伪静态配置&#xff1a; location / { try_files $uri $uri/ /index.html; } thinkphp 路由伪静态配置 location ~* (runtime|application)/{ return 403; } location / { if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s$1 last; break; } }

【Java】基础语法介绍

目录 一、注释 二、标识符与关键字 三、输入和输出 3.1 输出 3.2 输入 四、数据类型 3.1 基本数据类型 3.2 引用数据类型 3.3 var关键字 五、运算符 六、分支和循环 5.1 分支 5.2 循环 七、类和对象 6.1 类的定义与对象的创建 6.2 空对象 6.3 类的属性 6.4 类…

优化下载性能:使用Python多线程与异步并发提升下载效率

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 普通请求下载📝 使用多线程加速下载📝 使用异步编程加速下载📝 总结 📝⚓️ 相关链接 ⚓️📖 介绍 📖 你是否因为下载速度慢而感到焦虑?特别是在下载大型文件时,等待进度条慢慢移动的感觉真的很…

【Head-DETR系列(7)】DETR 代码分析

在nuscens数据集上&#xff0c; Results and Models BackboneModelLr schdMem (GB)Inf time (fps)box APConfigDownloadR-50DETR150e7.940.1configmodel | log 我们先看检测器 /mmdetection-2.28.2/mmdet/models/detectors/detr.py def forward_train(self,img,img_metas,gt_…

利基网站收入报告(更新至十月)

欢迎来到我的利基网站收入报告。这是我揭露当月我所有网站收入情况的地方。目前&#xff0c;我主要专注于一个核心网站&#xff0c;其余的不是重心&#xff0c;有些可能会在不久的将来出售。 为什么我分享我的利基网站收入报告&#xff1f; 需要旧报告&#xff1f; 2023年10月…

JSON包新提案:用“omitzero”解决编码中的空值困局

Go标准库是Go号称“开箱即用”的重要因素&#xff0c;而标准库中的encoding/json包又是标准库最常用的Go包。虽然其性能不是最好的&#xff0c;但好在由Go团队维护&#xff0c;对JSON规范兼容性好&#xff0c;且质量很高。但json包也不是没有“瑕疵”的&#xff0c;Go官方继mat…

6款SSL证书实用工具,格式转换/CSR生成等全都免费使用!

俗话说“工欲善其事&#xff0c;必先利其器”&#xff0c;SSL证书作为保护网站数据传输安全的重要部分&#xff0c;我们在申请、签发、部署安装SSL证书的时候&#xff0c;可能会涉及到CSR文件生成、获取证书链、转换证书格式等需求&#xff0c;这时候有对应的工具就可提高工作效…

基于SpringBoot的考研助手系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

干货| Python代码性能优化总结

代码优化原则 本文会介绍不少的 Python 代码加速运行的技巧。在深入代码优化细节之前&#xff0c;需要了解一些代码优化基本原则。 这里插播一条粉丝福利&#xff0c;如果你正在学习Python或者有计划学习Python&#xff0c;想要突破自我&#xff0c;对未来十分迷茫的&#xf…

超全网络安全面试题汇总(2024版)

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…