前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++程序转化语义

C++程序转化语义

作者头像
Ch_Zaqdt
发布2020-03-12 18:05:06
3460
发布2020-03-12 18:05:06
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACM

显示的初始化操作

        建立一个类A,首先实例化一个对象x

代码语言:javascript
复制
A x;

       下面有三种显示的初始化操作(也就是说在定义的时候就进行初始化操作)

代码语言:javascript
复制
A x1 = x;

A x2(x);

A x3 = (x);

       那么对于我们来说,可以理解为在实例化对象的时候通过拷贝构造函数进行了拷贝操作,那么实际上在编译器层面看来,其实将上面的一句代码分成了两句。

代码语言:javascript
复制
A x1;       // 这里没有调用默认构造函数
x1.A::A(x);

       但是对于第一句的实例化对象来说,站在编译器的角度来看不会主动的去调用构造函数,所以这里没有去调用默认构造函数,而是在第二行调用了拷贝构造函数进行拷贝操作。

参数的初始化

       参数的初始化操作是指将对象作为函数的参数进行传递,先来看一下下面的这个代码:

代码语言:javascript
复制
#include <iostream>
using namespace std;

class A {
public:
	A() {
		cout << "默认构造函数" << endl;
	}
	A(const A&) {
		cout << "拷贝构造函数" << endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};

void func(A x) {
	return ;
}

int main()
{
	A x;
	func(x);
	return 0;
}

       执行结果为:

默认构造函数 拷贝构造函数 析构函数 析构函数

       在之前学习类的时候就知道会是这样的输出的一种情况,实际上在以前的老版本的编译器中所运行的代码实际上是这样的:

代码语言:javascript
复制
#include <iostream>
using namespace std;

class A {
public:
	A() {
		cout << "默认构造函数" << endl;
	}
	A(const A&) {
		cout << "拷贝构造函数" << endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};

void func(A &x) {
	return ;
}

int main()
{
	A x;
	A tmpx;
	tmpx.A::A(x);
	func(tmpx);
	tmpx.A::~A();
	return 0;
}

       是在函数外面实例化一个临时对象然后作为引用传到函数中去,在函数结束的时候析构,但是这是在老版本的编译器中是这样的,毕竟深度探索C++对象模型这本书也比较久远了,所以现在的编译器还是直接通过显示的初始化进行操作的,也就是先实例化一个对象,然后再调用拷贝构造函数,在函数内的对象也仅限于函数内使用。

返回值初始化

       返回值初始化是指一个函数返回一个类对象的初始化操作,我们一般写的代码是下面这样的:

代码语言:javascript
复制
#include <iostream>
using namespace std;

class A {
public:
	A() {
		cout << "默认构造函数" << endl;
	}
	A(const A&) {
		cout << "拷贝构造函数" << endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};

A func() {
	A x1;
	//...
	return x1;
}

int main()
{
	A x = func();
	return 0;
}

       这个很好理解,在函数中实例化一个对象,然后将其返回并拷贝给x对象。而在编译器的视角来看,它用了一种很巧妙的方法来实现这个操作,先来看一下编译器的处理代码:

代码语言:javascript
复制
#include <iostream>
using namespace std;

class A {
public:
	A() {
		cout << "默认构造函数" << endl;
	}
	A(const A&) {
		cout << "拷贝构造函数" << endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};

void func(A &x) {    // 返回值为空, 参数为引用
	A x1;        // 这里不会调用默认构造函数
	//...        做一些操作
	x.A::A(x1);      // 在这里将x1拷贝给x
	return ;
}

int main()
{
	A x;
	func(x);
	return 0;
}

       这个操作就是将主函数中的x对象的地址传进去,然后在函数中实例化一个临时对象并进行一系列操作后,再拷贝构给x对象,那么实际上就是将结果拷贝给了主函数中的x对象。

       有时候我们在主函数中不需要实例化一个对象,而去调用func函数返回的对象直接调用该对象的成员函数,比如下面的这个代码:

代码语言:javascript
复制
A func() {
	A x1;
	//...        做一些操作
	return x1;
}

int main()
{
	func().Afunc();      // Afunc为成员函数
	return 0;
}

       那么在编译器看来,这个代码是这样的,实现方法也很巧妙:

代码语言:javascript
复制
void func(A &x) {
	A x1;
	//...        做一些操作
	x1.A::A(x);       // 将x1拷贝给x
	return ;
}

int main()
{
	A x;            // 不会调用默认构造函数
	(func(x),x).Afunc();      // Afunc为成员函数
	x.A::~A();
	return 0;
}

       这个方法巧妙就巧妙在(func(x), x).Afunc();这句,这句代码前面使用了逗号表达式,也就是说func(x)使x有了一些值,然后(func(x), x)的值就是x,然后再去调用x.Afunc()。

       如果我们要使用函数指针的形式,比如下面的形式:

代码语言:javascript
复制
A func() {
	A x1;
	//...        做一些操作
	return x1;
}

int main()
{
	A(*pf)();
	pf = func;
	pf().Afunc();
	return 0;
}

       那么编译器的视角就是下面这个样子:

代码语言:javascript
复制
void func(A &x) {
	A x1;
	//...        做一些操作
	x.A::A(x1);      // 将x1拷贝给x
	return ;
}

int main()
{
	A x;      // 不调用默认构造函数
	void (*pf)(A&);
	pf = func;
	pf(x);
	x.Afunc();
	x.A::~A();
	return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 显示的初始化操作
  • 参数的初始化
  • 返回值初始化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档