一些碎碎念以及类和对象零碎知识点补充

简介: 一些碎碎念以及类和对象零碎知识点补充

萌新想说的一些话


其实本篇博客的内容应该是出现在上一篇博客当中的


当时萌新的心理状态是这样子的


今天已经很晚了 这些内容老师也只是上课提了一嘴 要不就先不写了吧 反正自己能记住 (其实并不会 刚刚的我在写博客中回顾前几天的知识发现对内联函数印象已经很低了)


这里趁机再回顾一遍 内联其实是对编译器一种建议 类似于宏的作用 展开函数 避免建立栈帧


然后写完上篇博客提交之后我就开始刷视频 刷着刷着我就开始对自己刚刚的行为思考起来


为什么我会开始偷懒了?


两个月前是什么原因让我开始学编程的呢?


当时的自己跟朋友们刚刚做完一些项目 由于大环境的原因所有的工作都停掉了


手里也还有点积蓄于是便开始游戏人生了一段时间


但是我慢慢的发现 每天花天酒地好像不会让我变得幸福 反而是一股空虚感占据了我的生活


我应该开始做点事 不能这样荒废下去了


于是我开始思考 应该学点什么东西呢?


正好一位朋友在字节做网络安全工程师 看他朋友圈发的一些跟编程相关的东西和我在电影中对于黑


客这个角色的仰慕 我决定了


我要开始学编程 我要称为一名很厉害的黑客


之后便是上网找资源


理所当然 我找到了bilibili排名第一c语言视频 也就是鹏哥的课 开始跟着鹏哥学习


我到现在还清楚的记得当时打下这段代码时的激动


cdba132ca1a14863ba1c3140ef79faf1.png


随着学习的深入 我发现自己对于编程的热爱愈发的强烈


我决定了 我要学好编程 我要将它当作我的终生事业


之后在鹏哥的不断强调之下 萌新开始了写博客


两个月 120篇博客 绝对不可能是将写博客这件事当作是一个任务的人能够做到的


那为什么我现在开始偷懒了呢? 我的初心变了嘛?


萌新觉得最大的可能就是因为我已经将写博客这件事习以为常了


这种习惯有利有弊


利在于养成了每天总结知识的好习惯


弊在于我们很容易轻视我们的日常


能够每天学习 接受高等教育 每天进步是一件值得非常珍惜的事


但是因为每天都在经历这件事 我反而觉得这没有什么大不了的


这是一个很愚蠢的想法 我应该想办法来对抗它


之后在萌新决定写这篇博客的时候就开始思考 我应该怎么对抗这种思想呢?


因为这种想法源自于对于当下日常的忽视


所以说萌新决定从这三个方面来改变


1.每天冥想五分钟

其实冥想这个习惯萌新已经坚持很久了 在回到学校之后由于课业繁忙反而开始断断续续的

不应该 实在是不应该 不可能每天的生活忙到五分钟的空闲都抽不出来

希望自己能够重视冥想这件事 好好感受当下


2.每天review自己的日常


我应该在每天空出来一段时间 (最好是晚上)回顾下今天做了什么 有没有认真去做 有没有珍惜当下的学习机会


3.改变观念


我的初心是我很热爱编程 学习到新的知识会让我很开心 不要被别的奖励机制蒙蔽住(比如粉丝 或者说博文上榜 奖金 虽然确实能给自己带来一些愉悦 但是这些不应该是我所追求的目标 它们只是我成长路上的附属品)


最后再来一遍自我介绍吧


萌新现在是一名大二学生 希望能和大家一起进步!


匿名对象


概念介绍


我们先来看下面的代码


class A
{
public:
  A(int a = 0)
  :_a(a)
  {
  cout << "A(int a)" << endl;
  }
  ~A()
  {
  cout << "~A()" << endl;
  }
private:
  int _a;
};
class Solution {
public:
  int Sum_Solution(int n) {
  //...
  return n;
  }
};
int main()
{
  A aa1;
}


我们再定义一个对象的时候一般习惯这么定义


A aa1;


但是呢 这里就有一种特殊的写法


A() ;


是不是很奇怪? 这个时候编译器就会疑惑了 这里到底是一个对象定义还是一个函数声明呢?


我们C++中给这种语法规定了一个名词 叫做匿名对象


匿名对象有两个特点


1 没有对象名 这个不用萌新演示大家应该也能看明白吧 就是字面意思

2 他的生命周期只有一行


那么这点要怎么理解呢?


我们上代码


a643a55173084cdabc77e830b0c6c1f2.png


我们可以发现 确实程序走到我们test这一行的时候A()的生命周期就结束了(调用析构函数)


应用场景


假设我们只是想调用类里面的一个方法


这个时候创建一个类就显得很多余了 那么我们的匿名对象就派上用场了


0aefd046cd75411cb170616258ef9896.png


它的用处就在于此


拷贝对象时编译器的一些优化


这里最先由我曹姐姐总结完毕 萌新在这里就直接使用这些代码来讲解了

曹姐姐博客 @曹姐姐的博客


编译器在传参和传返回值的时候会做一些优化


为了成为更优秀的工程师 写出更好的代码 我们了解这些优化的场景是必要的


PS:C++中标准中并没有规定必须要做这样子的优化 编译器之间的内卷罢了 所以说一些老版本的编译器是不会有这个优化的


class A
{
public:
  A(int a = 0)
  :_a(a)
  {
  cout << "A(int a)" << endl;
  }
  A(const A& aa)
  :_a(aa._a)
  {
  cout << "A(const A& aa)" << endl;
  }
  A& operator=(const A& aa)
  {
  cout << "A& operator=(const A& aa)" << endl;
  if (this != &aa)
  {
    _a = aa._a;
  }
  return *this;
  }
  ~A()
  {
  cout << "~A()" << endl;
  }
private:
  int _a;
};
void f1(A aa)
{}
A f2()
{
  A aa;
  return aa;
}
A f3()
{
  /*A aa(10);
  return aa;*/
  return A(10);
}
// 《深度探索C++对象模型》中的知识
int main()
{
  // 优化场景1
  //A aa1 = 1;  // A tmp(1) + A aa1(tmp) -> 优化 A aa1(1)
  // 优化场景2
  //A aa1(1); // 优化前
  //f1(aa1);
  //f1(A(1));  // 构造 + 拷贝构造  -> 优化 构造   优化后
  //f1(1);  // 构造 + 拷贝构造  -> 优化 构造      优化后
    // 优化场景3
  // f2();   // 构造+拷贝构造
  //A ret = f2(); // 构造+拷贝构造+拷贝构造 ->优化 构造+拷贝构造
    // 优化场景4:
  /*A ret;   优化前
  ret = f2();*/
  A ret = f3();  //  构造+拷贝构造+拷贝构造 -> 优化 -> 构造
  return 0;
}


优化场景一 赋值


优化前


A tmp(1); //构造一个临时变量
A aa1 = tmp; // 传参给对象 aa1


我们来看看运行结果

be0a7b53ab924708808916afd2636832.png


我们可以发现 这里调用了一次构造 一次拷贝


然后我们优化下试试


A aa1 = 1; // 传参给对象 aa1


运行结果如下


e255bead6afc49eab0271b671ed86922.png


我们会发现 这个时候编译器优化了一次拷贝函数 编译器直接开始构造aa1了


当然这里使用匿名对象也可以

a6a754190f63491e98f217aeb020786e.png


优化场景二 传参


我们都知道 函数在被当成参数传递的时候都会进行一个拷贝构造


如图

f5ef61e7d27d422c80e4ddc4d83538a9.png


那么这个时候我们的匿名对象就派上用处了

e1cf0a05b48d44609c1f5e51180274eb.png


将我们的匿名对象传递进去就能够避免一次拷贝构造


这里说明了什么? 我们学习的知识之间并不是孤立的 而是相互练联系的 所以说我们务必重视每一个知识点


当然我们这里直接传1进去进行一个隐式类型转换也能优化


812751a38ce040839a907a119b11b373.png


优化场景三 返回值

17f097bf4f044404ab119d1b5f2cc29d.png


我们发现当我们调用f2这个函数的时候 它首先会构造一次对象 之后拷贝一次对象


但是假如我们使用一个返回值接受的话


4d11448aa0544d2e8a40f015fbb14665.png


咦 我们发现依然是两次 并没有优化啊


其实不是这样子的


因为这里面还多了一步对ret 拷贝构造的操作 本来应该是三步 编译器直接省略掉了其中一步


那么大家想想看 这里优化掉的是哪一步拷贝构造呢?


函数内的? 还是 拷贝构造ret时的?


很显然 优化掉的是函数内的拷贝构造


因为如果优化的是ret的拷贝构造不就跟优化场景三优化前没区别了嘛


优化场景四 综合


代码如下


A f2()
{
  A aa;
  return aa;
}


A ret;   //优化前
  ret = f2();


运行结果如下


356b446172344040b659320f1c28f190.png


这里简单说下


创建ret的时候一次构造


到f2函数里面


创建aa一次构造


赋值给ret的时候一次拷贝构造


接下来我们来看优化场景


cbc8bef7d1984e60b21310dc72b77e7e.png


我们这里是不是赋值的时候使用匿名对象赋值 这是一次优化


做参数的时候没有参数出现


做返回值的时候返回匿名对象 这是一次优化


所以说到了最后的赋值就是和场景一一模一样了


所以说会是优化成一次构造


总结


本篇博客写了一些萌新想说的话以及类和对象剩余知识点

由于作者水平优先 错误在所难免 希望大佬看见能够及时指正!


如果这篇博客有帮助到你 别忘了一键三连啊


阿尼亚 哇酷哇酷!

相关文章
|
存储 算法
【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(一)
【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(一)
102 0
|
存储 缓存 Python
一些零碎的小知识点
一些零碎的小知识点
|
算法
【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(二)
【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(二)
72 0
|
编译器 C++
【C++精华铺】6.C++类和对象(下)类与对象补充及编译器优化
构造函数的初始化列表及其行为、static成员(函数,变量)、友元(函数,类)、内部类、匿名对象、对象拷贝时的编译器优化
|
编译器 C++
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(3)
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(3)
91 0
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(3)
|
存储 编译器 C++
【C++初阶】二、类与对象(中篇)
目录 一、类的6个默认成员函数 二、构造函数 2.1 构造函数概念 2.2 构造函数的特性 三、析构函数 3.1 析构函数的概念 3.2 析构函数的特性 四、拷贝构造函数 4.1 拷贝构造函数概念 4.2 拷贝构造函数的特性 五、赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 六、const 成员 七、取地址及const取地址操作符重载
58 0
|
存储 编译器 C语言
初阶C++——C++第二节——类和对象(大全篇)
万物皆对象。因为只要我们去研究它,它就成为我们的对象。在编程世界,其可以指所有的数据。并且该说法尤其是与类同时出现的频次较高。
84 0
初阶C++——C++第二节——类和对象(大全篇)
|
编译器 C++
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(1)
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(1)
121 0
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(1)
|
编译器 C++
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(2)
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(2)
104 0
【C++】—— 类和对象(中)一张图带你搞清楚6个默认成员函数+万字总结 复习全靠它(2)