【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++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL 中 ROW_NUMBER() 函数最佳实践

《MySQL中ROW_NUMBER()函数最佳实践》MySQL中ROW_NUMBER()函数,作为窗口函数为每行分配唯一连续序号,区别于RANK()和DENSE_RANK(),特别适合分页、去重... 目录mysql 中 ROW_NUMBER() 函数详解一、基础语法二、核心特点三、典型应用场景1. 数据分

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C