总结
至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:
- 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
- 项目经历:只写明星项目,描述遵循 STAR 法则;
- 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;
以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频
现在呢,又会产生什么样的结果嘞?
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;*/
return NULL;
}
结果:
test() //构造t1
test() //构造t2
test(const test&) //构造形参t
test() //多了这个 构造temp(函数栈帧上的临时对象)
test(const test&) //还有这个 将temp复制给回调(main栈帧上的临时函数)
~test() //析构temp
~test() //析构形参
operator = //将回调赋值给t2
~test() //析构回调
~test() //析构t1
~test() //析构t2
VS
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;
}
int main() {
test t1;
test t2;
t2 = GetObject(t1);
cout << “***********************************************” << endl;
return 0;
}
我也不想多废话了,直接使用传地址调用即可。
test()
test()
test()
test(const test&)
~test()
operator =
~test()
~test()
~test()
好!直接省了一个复制构造函数和一个析构。
为什么回调会这么麻烦呢?因为当函数运行完的时候,temp生命周期也到头了呀!!!
所以需要在用一个临时变量去接住它,再传出来,再赋值。
那我现在不想这么麻烦了!!!
接下来:
test GetObject(test &t) {
int val = t.getdata();
cout << “-----------------------------------------------” << endl;
//返回临时对象
return test(val); //这个临时对象并没有产生
}
int main() {
test t1;
test t2;
t2 = GetObject(t1); //你会发现,临时对象不产生了,不记得?往前翻、
//“当使用临时对象复制给一个对象时。。。”
cout << “***********************************************” << endl;
return 0;
}
test() //t1
test() //t2
test() //直接构造main函数栈帧上的临时对象
operator = //将main函数栈帧上的临时对象赋值给t2
~test() //析构该临时对象
~test()
~test()
一次优化少两个函数,爽吧!!!
虽然一次调用少的不多,但是积少成多,是很可观的。
你以为我就到此为止了?
你错了,“我是没有极限的!!!”
哈哈哈,借用一下台词。
再看:
int main() {
test t1;
test t2 = GetObject(t1);
cout << “***********************************************” << endl;
最后
整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,
}
test() //t1
test() //t2
test() //直接构造main函数栈帧上的临时对象
operator = //将main函数栈帧上的临时对象赋值给t2
~test() //析构该临时对象
~test()
~test()
一次优化少两个函数,爽吧!!!
虽然一次调用少的不多,但是积少成多,是很可观的。
你以为我就到此为止了?
你错了,“我是没有极限的!!!”
哈哈哈,借用一下台词。
再看:
int main() {
test t1;
test t2 = GetObject(t1);
cout << “***********************************************” << endl;
最后
整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
[外链图片转存中…(img-MXt2iNgB-1715817640925)]
[外链图片转存中…(img-o0s3et8A-1715817640926)]
其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,