程序员写的代码,编译器在处理的时候会进一步把这些代码拆分,拆分成更容易被理解和实现的代码
#include <iostream>
using namespace std;
class X
{
public:
int m_i;
X(const X& tmpx) {
m_i = tmpx.m_i;
cout << "X类的拷贝构造函数被调用" << endl;
}
X() {
m_i = 0;
cout << "X类的构造函数被调用" << endl;
}
};
int main()
{
X x0;
x0.m_i = 15;
X x1 = x0;
X x2(x0);
// 分析这一行
X x3 = x0;
return 0;
}
X类的构造函数被调用
X类的拷贝构造函数被调用
X类的拷贝构造函数被调用
X类的拷贝构造函数被调用
以编译器的角度看这行代码
X x3 = x0;
切换到编译器角度,编译器会拆分成两个步骤(编译器视角)
- X x3; 步骤一:定义一个对象,为对象分配内存。从编译器视角来看,这句是不调用X类的构造函数
- x3.X::X(x0); 步骤二:直接调用对象的拷贝构造函数去了
总结:
编译器先创建对象,再调用对象的拷贝构造函数进行拷贝
#include <iostream>
using namespace std;
class X
{
public:
int m_i;
X(const X& tmpx) {
m_i = tmpx.m_i;
cout << "X类的拷贝构造函数被调用" << endl;
}
X() {
m_i = 0;
cout << "X类的构造函数被调用" << endl;
}
~X() {
cout << "X类的析构函数被调用" << endl;
}
};
void func(X tmpx)
{
return;
}
int main()
{
X x0;
func(x0);
return 0;
}
X类的构造函数被调用
X类的拷贝构造函数被调用
X类的析构函数被调用
X类的析构函数被调用
站在编译器的视角
func(x0);
编译器是在func
这个函数的空间内构造出来了tmpx
对象,然后在func
函数返回前,把tmpx
对象析构掉
一些老编译器的视角中
//以下这些可以认为是伪代码,并不代表在当代编译器上能够正确运行,只是借此了解编译稽内部具体都做了什么
X tmpobj; //编译然产生出来一个临时对象
tmpobj.X::X(x0);//调用拷贝构造函数
func(tmpobj); //用临时对象调用func
tmpobj.X::~X(); //func()被调用完成后,析构函数被调用
func函数的参数站在老编译器的角度也会做出调整,变成引用
void func(X &tmpx)
{
return;
}
#include <iostream>
using namespace std;
class X
{
public:
int m_i;
X(const X& tmpx) {
m_i = tmpx.m_i;
cout << "X类的拷贝构造函数被调用" << endl;
}
X() {
m_i = 0;
cout << "X类的构造函数被调用" << endl;
}
~X() {
cout << "X类的析构函数被调用" << endl;
}
};
X func()
{
X x0;
return x0;
}
int main()
{
X my = func();
// X my;
// my.func();
return 0;
}
X类的构造函数被调用
X类的拷贝构造函数被调用
X类的析构函数被调用
X类的析构函数被调用
站在编译器的视角下
void func(X &extra) //1.安插一个引用参数
{
X x0; //2.调用构造函数x0.X::X()
//...
extra.X::X(x0); //3.return之前安插一个对拷贝构造函数的调用
//return x0;
return;
}
看见了吧,并不是说直接在函数外复制了一个,而是通过改变函数形参,先引用进来,然后再对得到的别名进行拷贝构造函数。之前认为是在()
里完成的,但其实编译器是先引用再在函数体内执行拷贝构造函数。
编译器看main函数中代码
X my; // 从编译器的视角看,着里是不调用构造函数的,除非编译器主动增加代码my.X::X();
func(my);
最终
#include <iostream>
using namespace std;
class X
{
public:
int m_i;
X(const X& tmpx) {
m_i = tmpx.m_i;
cout << "X类的拷贝构造函数被调用" << endl;
}
X() {
m_i = 0;
cout << "X类的构造函数被调用" << endl;
}
~X() {
cout << "X类的析构函数被调用" << endl;
}
};
void func(X& extra)
{
X x0;
extra.X::X(x0);
return;
}
int main()
{
X my;
func(my);
return 0;
}
#include <iostream>
using namespace std;
class X
{
public:
int m_i;
X(const X& tmpx) {
m_i = tmpx.m_i;
cout << "X类的拷贝构造函数被调用" << endl;
}
X() {
m_i = 0;
cout << "X类的构造函数被调用" << endl;
}
~X() {
cout << "X类的析构函数被调用" << endl;
}
void functest() {
cout << "functest()成员函数被调用" << endl;
}
};
X func()
{
X x0;
return x0;
}
int main()
{
X my = func();
func().functest();
return 0;
}
编译器视角下的main函数
X my;
(func(my), my).functest(); //逗号运算符,先求解表达式1,再求解表达式2,整个表达式的值是表达式2的值
X(*pf); //定义函数指针
pf = func;
pf().functest();
编译器的视角
X my;
void (*pf)(X&);
pf = func;
pf(my);
my.functest();