【C++干货基地】面向对象核心概念 const成员函数 | 初始化列表 | explicit关键字 | 取地址重载

本文主要是介绍【C++干货基地】面向对象核心概念 const成员函数 | 初始化列表 | explicit关键字 | 取地址重载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


在这里插入图片描述

🎬 鸽芷咕:个人主页

 🔥 个人专栏: 《C++干货基地》《粉丝福利》

⛺️生活的理想,就是为了理想的生活!

引入

  哈喽各位铁汁们好啊,我是博主鸽芷咕《C++干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的城市有没有这种实惠又全面的零食基地呢?C++ 本身作为一门篇底层的一种语言,世面的免费课程大多都没有教明白。所以本篇专栏的内容全是干货让大家从底层了解C++,把更多的知识由抽象到简单通俗易懂。

⛳️ 推荐

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

文章目录

  • 引入
  • ⛳️ 推荐
  • 一、const 成员函数
    • 1.1 什么是const 成员函数
    • 1.2 const成员函数的注意事项
    • 总结
  • 二、取地址及const取地址操作符重载
    • 2.1 取地址操作的意义
  • 三、重新认识构造函数
    • 3.1构造函数体赋值
    • 3.2 初始化列表
      • 规则一
      • 规则二
  • 四、explicit关键字
    • 4.1 构造函数的隐式类型转换
    • 4.2 隐式转换的作用
    • 4.2 explicit关键字的使用

一、const 成员函数

1.1 什么是const 成员函数

cosnt 的成员函数其实就是在我们 函数的括号外 多加一个 const void Dlsplay() const

  • 其他的作用是修饰 隐含的 this 指针,使其不能修改。

在这里插入图片描述

1.2 const成员函数的注意事项

const 成员可以直接修饰this指针那么使用起来有什么要注意的嘛?

  • 下面我们看一下这些代码来思考一下
#include<iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}
private:int _year; // 年int _month; // 月int _day; // 日
};
void Test()
{Date d1(2022, 1, 13);d1.Print();const Date d2(2022, 1, 13);d2.Print();
}int main()
{Test();return 0;
}
  1. const对象可以调用非const成员函数吗?
  • 不能 const 对象调用非const成员会导致,权限的放大所以会出现错误
  1. 非const对象可以调用const成员函数吗?
  • 可以 非const 成员调用 const 成员函数属于权限的缩小,权限是可以缩小的
  1. const成员函数内可以调用其它的非const成员函数吗?
  • 不可以,这样会导致权限的放大
  1. 非const成员函数内可以调用其它的const成员函数吗?
  • 可以,非const 成员,调用const 成员是权限的缩小

总结

1. 在成员函数里如果我们只对成员变量读访问,那么建议加上 cosnt指针。
2. 在成员函数里如果我们要对成员变量进行修改,不能加上 cosnt指针。(否者修改不了成员变量)

二、取地址及const取地址操作符重载

2.1 取地址操作的意义

取地址操作符顾名思义,就对我们的 & 取地址符号进行重载使其能获取到成员变量的地址

  • 但是一般都是默认生成的,除非我们想让取地址符号取的是指定位置的地址
class Date
{
public:Date* operator&(){return this;}const Date* operator&()const{return this;}
private:int _year; // 年int _month; // 月int _day; // 日
};

三、重新认识构造函数

3.1构造函数体赋值

以往我们在定义构造函数的时候都是在构造函数内进行赋值的,那么我们创建成员变量是否也是在构造函数里面呢?

  • 如果构造函数是创建的话那么,我们声明成员变量的时候给的默认值是定义嘛?
class Date
{
public:
Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:
int _year = 2022;
int _month = 06;
int _day = 25;
};
  • 构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
  • 所以构造函数并不是初始化成员变量的地方,而我们在进行类声明的时候给的的默认值夜也只是声明

3.2 初始化列表

在C++中规定了所有成员变量在初始化的时候都是在初始化列表进行初始化的

  • 初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟
    一个放在括号中的初始值或表达式。
class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)

规则一

  • 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

这个我相信很好了解,初始化列表不管我们写没写都会在初始化列表进行初始化

  • 所以对于简单的变量初始化建议使用初始化列表
  • 一些复杂的类初始化可以使用在构造函数体内进行初始化

规则二

  • 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

🍸 代码演示:

class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout<<_a1<<" "<<_a2<<endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}
  • 大家猜一猜这个程序运行会出现什么情况呢?

  • A. 输出1 1 B.程序崩溃

  • C.编译不通过D.输出1 随机值

这里的答案是选D
虽然我们在初始化列表先写的是 _a1 但是初始化列表是按照声明的顺序来进行初始化的,对 _a2(_a1) 进行初始化的时候 __a1 还是一个随机值,_a2 就被赋值成了 _a1 的随机值

四、explicit关键字

4.1 构造函数的隐式类型转换

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值
的构造函数,还具有类型转换的作用。

class A
{
public:A(int x){this->_x = x;cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
private:int _x;
};
int main()
{A a1(1);A a2 = 3;return 0;
}

这里我们既可以使用构造函数来进行赋值,还可以使用隐式类型转换的方法来进行赋值。

  • 其主要原理是 使用 = 号赋值时,会先用 1 构造一个临时变量然后再调用拷贝构造构造函数
  • 也就是 先构造->在拷贝构造

但是编译器目前太智能了,对同一个表达式连续的构造会合二为一优化为一步
在这里插入图片描述

  • 除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。
class Data
{
public:Data(int year, int month = 10, int day = 1){cout << "data()" << endl;}~Data(){cout << "~data()" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Data a1(2021);Data a2 = 2022;return 0;
}

4.2 隐式转换的作用

隐式转换可以说是非常的好用了以后我们在很多地方都可以用到,以往我们使用链表存储类的话每次push 都需要,push 成员变量,但是有了隐式类型转换就可以直接插入自动转换为我们需要的类了。

  • 而且我们在类里面去给其他类进行使用缺省值的时候也是非常方便
class C
{
public://explicit C(int x = 0)C(int x = 0):_x(x){}C(const C& cc){cout << "C(const C& cc)" << endl;}private:int _x;
};C xx(1);//定义全局变量来赋缺省值class B
{
private:// 缺省值int a = 1;int* p1 = nullptr;int* p2 = (int*)malloc(4);C cc1 = xx;  // 虽然可以,但是很费劲C cc2 = 2;
};
  • push 插入时直接使用隐式类型转换,不需要在插入相同类型的类了
class C
{
public://explicit C(int x = 0)C(int x = 0):_x(x){}C(const C& cc){cout << "C(const C& cc)" << endl;}private:int _x;
};
class Stack
{
public:void Push(const C& c){//}
};int main()
{Stack st;C cc3(3);st.Push(cc3);st.Push(4);return 0;
}

4.2 explicit关键字的使用

explict 的关键字是用来修饰构造函数的一旦使用了 explicit 修饰构造函数,禁止类型转换
在这里插入图片描述


class A
{
public:explicit A(int x){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
private:int _x;
};class Data
{
public:explicit Data(int year, int month = 10, int day = 1){cout << "data()" << endl;}~Data(){cout << "~data()" << endl;}
private:int _year;int _month;int _day;
};int main()
{A a1 = 2;Data a2 = 2020;return 0;
}

在这里插入图片描述

这篇关于【C++干货基地】面向对象核心概念 const成员函数 | 初始化列表 | explicit关键字 | 取地址重载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/921701

相关文章

Python进阶之列表推导式的10个核心技巧

《Python进阶之列表推导式的10个核心技巧》在Python编程中,列表推导式(ListComprehension)是提升代码效率的瑞士军刀,本文将通过真实场景案例,揭示列表推导式的进阶用法,希望对... 目录一、基础语法重构:理解推导式的底层逻辑二、嵌套循环:破解多维数据处理难题三、条件表达式:实现分支

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

深度解析Python yfinance的核心功能和高级用法

《深度解析Pythonyfinance的核心功能和高级用法》yfinance是一个功能强大且易于使用的Python库,用于从YahooFinance获取金融数据,本教程将深入探讨yfinance的核... 目录yfinance 深度解析教程 (python)1. 简介与安装1.1 什么是 yfinance?

MySQL中REPLACE函数与语句举例详解

《MySQL中REPLACE函数与语句举例详解》在MySQL中REPLACE函数是一个用于处理字符串的强大工具,它的主要功能是替换字符串中的某些子字符串,:本文主要介绍MySQL中REPLACE函... 目录一、REPLACE()函数语法:参数说明:功能说明:示例:二、REPLACE INTO语句语法:参数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

python中update()函数的用法和一些例子

《python中update()函数的用法和一些例子》update()方法是字典对象的方法,用于将一个字典中的键值对更新到另一个字典中,:本文主要介绍python中update()函数的用法和一些... 目录前言用法注意事项示例示例 1: 使用另一个字典来更新示例 2: 使用可迭代对象来更新示例 3: 使用

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成