【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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数

python中的高阶函数示例详解

《python中的高阶函数示例详解》在Python中,高阶函数是指接受函数作为参数或返回函数作为结果的函数,下面:本文主要介绍python中高阶函数的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录1.定义2.map函数3.filter函数4.reduce函数5.sorted函数6.自定义高阶函数

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

Python中的sort方法、sorted函数与lambda表达式及用法详解

《Python中的sort方法、sorted函数与lambda表达式及用法详解》文章对比了Python中list.sort()与sorted()函数的区别,指出sort()原地排序返回None,sor... 目录1. sort()方法1.1 sort()方法1.2 基本语法和参数A. reverse参数B.

Java Instrumentation从概念到基本用法详解

《JavaInstrumentation从概念到基本用法详解》JavaInstrumentation是java.lang.instrument包提供的API,允许开发者在类被JVM加载时对其进行修改... 目录一、什么是 Java Instrumentation主要用途二、核心概念1. Java Agent

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2