(C++对象模型):程序转化语义

程序转化语义

  • 我们写的代码,编译器会对代码进行拆分,拆分成编译器更容易理解和实现的代码。
  • 看一看编译器是如何解析这些代码的。
  • 站在程序员角度/站在编译器角度  
  • 程序员看代码视角 和 编译器看代码视角之间不断切换。

定义时初始化对象

class X
{
public:
	int m_i;
	X(const X& tmpx)
	{
		m_i = tmpx.m_i;
		cout << "拷贝构造函数被调用" << endl;
	}
	X()
	{
		m_i = 0;
		cout << "构造函数被调用" << endl;
	}
};

int main()
{
	
	X x0;
	x0.m_i = 15;
	X x1 = x0;        // 定义的时候初始化,调用拷贝构造函数
	X x2(x0);         // 定义的时候初始化,调用拷贝构造函数
	X x3 = (x0);      // 定义的时候初始化,调用拷贝构造函数
}
  • 输出结果:

  • 切换到编译器角度,编译器会拆分成两个步骤(编译器视角)
    • X x3;               步骤一:定义一个对象,为对象分配内存。从编译器视角来看,这句是不调用X类的构造函数
    • x3.X::X(x0);    步骤二:直接调用对象的拷贝构造函数去了
  • 总结:
    • 编译器先创建对象,再调用对象的拷贝构造函数进行拷贝

参数的初始化

class X
{
public:
	int m_i;
	X(const X& tmpx)
	{
		m_i = tmpx.m_i;
		cout << "拷贝构造函数被调用" << endl;
	}
	X()
	{
		m_i = 0;
		cout << "构造函数被调用" << endl;
	}
	~X()
	{
		cout << "析构函数被调用" << endl;
	}
};

void func(X tmpx)
{
	return;
}

int main()
{
	X x0;
	func(x0);
	return 1;
}
  • 输出结果

  • 程序员角度:在传参时,调用拷贝构造函数将x0拷贝给tmpx,函数执行完毕,析构tmpx。
  • 现代编译器角度:函数先创建tmpx对象,然后调用该对象的拷贝构造函数将x0拷贝给tmpx。类似于 X tmpx(x0)的执行过程。

老编译器视角

  • X tmpobj;                      编译器产生一个临时对象
  • tmpobj.X::X(x0);           调用拷贝构造函数
void func(X tmpx)
{
	return;
}
老编译器看func(老编译器角度)
void func(X &tmpx)
{
	return;
}
  • func(tmpobj);                用临时对象调用func
  • tmpobj.X::~X();              func()被调用完成后,本析构被调用
  • 归纳:老编译器先在外面将临时对象构造出来,再以引用的方式传给函数(将传值方式改为引用)。

返回值初始化

class X
{
public:
	int m_i;
	X(const X& tmpx)
	{
		m_i = tmpx.m_i;
		cout << "拷贝构造函数被调用" << endl;
	}
	X()
	{
		m_i = 0;
		cout << "构造函数被调用" << endl;
	}
	~X()
	{
		cout << "析构函数被调用" << endl;
	}
};

X func()
{
	X x0;
	//....
	return x0;   
}


int main()
{
	X my = func();
	return 1;
}
  • 输出结果(程序员视角解析):

  • 编译器对上述代码的理解(编译器角度)
    • X my;          只是生成对象my,不会调用X的构造函数
    • func(my); 
  • 编译器角度的func
void func(X &extra)
{
    X x0; //从编译器角度,这里不调用X的构造函数
    //...
    //...
    extra.X::X(x0);  //调用拷贝构造函数,将x0拷贝给外部传来的引用
    return;
}

给类增加一个成员函数

class X
{
public:
	int m_i;
	X(const X& tmpx)
	{
		m_i = tmpx.m_i;
		cout << "拷贝构造函数被调用" << endl;
	}
	X()
	{
		m_i = 0;
		cout << "构造函数被调用" << endl;
	}
	~X()
	{
		cout << "析构函数被调用" << endl;
	}
	void functest()
	{
		cout << "functest()被调用" << endl;
	}
};

X func()
{
	X x0;
	//....
	return x0;   
}


int main()
{
	func().functest();
	return 1;
}
  • 输出结果:

  • 程序员视角:
    • func().functest();
  • 编译器视角
  • X my;   不会调用X的构造函数
  • (func(my), my).functest();     逗号表达式:先计算表达式1,再计算表达式2,整个逗号表达式的结果是表达式2的值;
  • 其中(func(my)为:
void func(X &extra)
{
    X x0; //从编译器角度,这里不调用X的构造函数
    //...
    //...
    extra.X::X(x0);  //调用拷贝构造函数,将x0拷贝给外部传来的引用
    return;
}

猜你喜欢

转载自blog.csdn.net/baidu_41388533/article/details/108670779
今日推荐