C++编程经验(8):对象优化,试试(2)

总结

无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

最后我整理了一些面试真题资料,技术知识点剖析教程,还有和广大同仁一起交流学习共同进步,还有一些职业经验的分享。

面试了阿里,滴滴,网易,蚂蚁,最终有幸去了网易【面试题分享】

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

using namespace std;

class test {

public:

test(int a = 10) :ma(a) { cout << “test()” << endl; }

~test() { cout << “~test()” << endl; }

test(const test& t) :ma(t.ma) { cout << “test(const test&)” << endl; }

test& operator = (const test& t) {

cout << "operator = " << endl;

ma = t.ma;

return *this;

}

private:

int ma;

};


案例一:

int main() {

test t1;

test t2(t1);

test t3 = t1;

//test(20) 显示生成临时对象,生存周期为所在的语句

test t4 = test(20);

cout << “***********************************************” << endl;

return 0;

}

可以自己猜一下打印结果。

test()

test(const test&)

test(const test&)

test()


~test()

~test()

~test()

~test()

由上述结果可以看出:

int main() {

test t1; //调用test(int)

test t2(t1); //调用test(const test&)

test t3 = t1; //调用的依旧是test(const test&)

//test(20) 显示生成临时对象,生存周期为所在的语句

test t4 = test(20); //调用的是test(int)

//这里本应该是先初始化一个临时对象,再讲临时对象拷贝给t4,

//但事实是直接为t4调用一个构造函数,将20的值传入,这是C++在 构造对象 时的优化

//这一点可以从最后的四次析构得到应证

cout << “***********************************************” << endl;

return 0;

}


案例二:

在上面的基础上加上两行:

int main() {

test t1;

test t2(t1);

test t3 = t1;

//test(20) 显示生成临时对象,生存周期为所在的语句

test t4 = test(20);

t4 = t2;

t4 = test(30);

cout << “***********************************************” << endl;

return 0;

}

可以再想想接下来的结论:

test()

test(const test&)

test(const test&)

test()

operator =

test()

operator =

~test()


~test()

~test()

~test()

~test()

t4 = t2; // 这里调用了复制构造函数

t4 = test(30); // 这里产生了临时对象

//与上面的情况有所不同的是,这里是给一个对象进行赋值,而上面是构造

//所以这里先使用构造函数构造了一个临时对象,再使用复制构造函数将临时对象复制到t4

//离开了这条语句之后,临时对象的生命周期结束,调用析构


operator =

test()

operator =

~test()


案例三:

在上面的基础上再进行添加:

int main() {

test t1;

test t2(t1);

test t3 = t1;

//test(20) 显示生成临时对象,生存周期为所在的语句

test t4 = test(20);

t4 = t2;

t4 = test(30);

t4 = (test)30;

t4 = 40;

cout << “***********************************************” << endl;

return 0;

}

现在呢,又会产生什么样的结果嘞?

test()

test(const test&)

test(const test&)

test()

operator =

test()

operator =

~test()

test()

operator =

~test()

test()

operator =

~test()


~test()

~test()

~test()

~test()

t4 = (test)30; //强制类型转换

//编译器会去查看类有没有对应的构造函数

//如果有,则生成一个临时对象,跟上面那结尾那个一样

t4 = 40;

//这个也几乎一样道理,不过上面的是显示类型转换,下面这个是隐式类型转换


operator =

~test()

test()

operator =

~test()


案例四:

在上面的基础上继续添加:

int main() {

test t1;

test t2(t1);

test t3 = t1;

//test(20) 显示生成临时对象,生存周期为所在的语句

test t4 = test(20);

t4 = t2;

t4 = test(30);

t4 = (test)30;

t4 = 40;

cout << “***********************************************” << endl;

//test* p = &test(40); //&要求一个左值

const test& pp = test(50); //非常量引用的对象必须是一个左值

cout << “***********************************************” << endl;

return 0;

}

好的,引用要求一个左值,让我们再来看一下结果:


test()


~test();

可以看到,引用对象调用了一个临时对象,出了作用域之后并不被析构掉,也即是说可以用。

但是函数结束之后也是要挂掉的。

这里是编译器审查的比较严格。


此外,再讲两个构造的调用时机:

1、全局对象的构造会在函数刚开始运行的时候。

2、静态对象在程序运行的时候会分配空间,但是在函数运行到的时候才会构造。

3、它们都在函数结束的时候析构。


接下来我们看函数调用中的对象优化。


案例五:

在上面的基础上,我们在类外再加这么一个函数:

test* GetObject(test t) {

int val = t.getdata();

test temp(val);

return &temp;

}

这里是不能这么写的,因为 temp(val) 是一个栈内临时对象,在函数结束的时候就会被析构的,如果编译不过就算了,我的VS编译过了,于是卡死了,果然没有让我失望哈。


案例六:

一波微调

test GetObject(test t) {

//不能返回局部或临时对象的指针或引用

int val = t.getdata();

test temp(val);

return temp;

}

//第一个main,做参照

int main() {

test t1;

test t2;

cout << “***********************************************” << endl;

return 0;

}

//第二次运行的main

int main() {

test t1;

test t2;

t2 = GetObject(t1);

cout << “***********************************************” << endl;

return 0;

}

产生结果:

//第一次运行的main

test()

test()


~test()

~test()

//第二次运行的main

test()

test()

test(const test&)

test()

test(const test&)

~test()

~test()

operator =

~test()


~test()

~test()

差距好大。。

记住这里,一会儿要回来

那么,对比一下,结果就是:

t2 = GetObject(t1);

产生:

test(const test&)

test()

test(const test&)

~test()

~test()

operator =

~test()

这之间有什么离奇曲折的故事呢?

首先,t1 作为实参传递给形参,怎么传递的?复制构造函数嘛。

为什么这么说呢,咱凡事讲证据。

void GetObject(test t) {

int val = t.getdata();

cout << “***********************************************” << endl;

/*test temp(val);

return temp;*/

//return NULL;

}

int main() {

test t1;

test t2;

GetObject(t1);

cout << “***********************************************” << endl;

return 0;

}

我把那底下的都注释了,返回值也免了,于是得出这么一个结果:

test() //t1

test() //t2

test(const test&) //构造形参


~test() //说明是离开了函数作用域才被析构掉的


~test()

~test()

可以说明这个传参的过程只执行了一次复制构造函数。

那么,对比上面那次,剩下的这段又是怎么肥四呢?:

test()

test(const test&)

~test()

~test()

operator =

再修改,给函数一个返回值看看:

test GetObject(test t) {

int val = t.getdata();

cout << “-----------------------------------------------” << endl;

/*test temp(val);

return temp;*/

return NULL;

}

运行结果:

test()

test()

test(const test&)


test()

~test()

~test()


~test()

~test()

去掉前面的影响,可以看到返回值对函数的影响是:产生了一个构造函数,并产生了一个析构函数。

为了探究这个这个析构函数是在哪里产生的,我给了main函数接收函数返回值的权利(其实用脚指头想都知道是在main里面析构的),不过用脚指头想不到的是,在 main 的什么部位析构,是像 t1、t2 一样在函数结束之后吗?

int main() {

test t1;

test t2;

t2 = GetObject(t1);

cout << “***********************************************” << endl;

return 0;

}

test()

test()

test(const test&)


test()

~test()

operator =

~test()


~test()

~test()

事实证明,这个返回值生成的对象在赋值之后便被析构。


现在,我们将封闭的代码解封,开对比下面两段代码的结果

test GetObject(test t) {

int val = t.getdata();

cout << “-----------------------------------------------” << endl;

test temp(val); //多了这行

cout << “-----------------------------------------------” << endl;

return temp;

}

VS

test GetObject(test t) {

int val = t.getdata();

cout << “-----------------------------------------------” << endl;

/*test temp(val);

return temp;*/

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

百度、字节、美团等大厂常见面试题

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

or =

~test()


~test()

~test()

事实证明,这个返回值生成的对象在赋值之后便被析构。


现在,我们将封闭的代码解封,开对比下面两段代码的结果

test GetObject(test t) {

int val = t.getdata();

cout << “-----------------------------------------------” << endl;

test temp(val); //多了这行

cout << “-----------------------------------------------” << endl;

return temp;

}

VS

test GetObject(test t) {

int val = t.getdata();

cout << “-----------------------------------------------” << endl;

/*test temp(val);

return temp;*/

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

[外链图片转存中…(img-O7xmAizR-1715817607581)]

[外链图片转存中…(img-fEC9fd3c-1715817607581)]

百度、字节、美团等大厂常见面试题

[外链图片转存中…(img-GpczUERW-1715817607581)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值