请教下派生类对象强制转换为基类对象,会不会有临时对象产生?如果有,为什么?

C++语言 码拜 10年前 (2015-05-11) 1146次浏览 0个评论
 

原帖地址http://bbs.csdn.net/topics/390793860,为了方便还是把示例代码贴下吧

class FBase
{

public:
	virtual void Set()
	{
		info = _T("FBase");
	}

	void PrintInfo()
	{
		_tprintf(_T("%s\n"), info);
	}

protected:
	TCHAR *info;
};


class FChild : public FBase
{
public:
	void Set()
	{
		info = _T("FChild");
	}

};
	FChild	child;
	child.Set();
	child.PrintInfo();
	((FBase)child).Set();
	child.PrintInfo();

结果是打印2次“FChild”。(FBase)child这句貌似有临时对象产生,但如果有的话却并没有调用到构造函数,如果没有的话下面这几个值都不相同,指针之间的转换还能看懂,对象间的强制转换有点不太明白这个转换过程发生了些什么,求指点。

FBase* pBase = (FBase*)&child;
FBase* pBase2 = &(FBase)child;
FBase* pBase3 = &(FBase)child;
同不懂,求教
40分
直接使用 (FBase)child 这种对象的转换是有临时对象产生的,调用的不是构造函数,而是拷贝构造函数

FBase(const FBase& b)
{
    //Copy Constructor code...
}

在使用多态的时候不能使用这种对象的强制转换,而应该使用指针或者引用(楼主肯定知道^^)。如果非要深究,应该是这么回事:

        FChild    child;
	child.Set();
	child.PrintInfo();	//print: FChild

	//对对象进行类型转换,调用默认的拷贝构造函数进行浅拷贝
	//此时b.info 指向 child.info 内存地址
	// b.vtable 指向 FBase::vtable
 	FBase b = (FBase)child;
	b.PrintInfo();		//print: FChild

	//给b.info 重新赋值,调用 FBase::Set()
 	b.Set();
	b.PrintInfo();		//print: FBase

	child.PrintInfo();  //print: FChild
引用 2 楼 Fire_Lord 的回复:

[/code]

感谢,(FBase)child 按照你说的应该是用child的基类部分拷贝构造一个匿名的FBase对象,可是还是不太明白这种转换为什么会有拷贝构造的调用,是标准有规定吗

引用 3 楼 zhousitiaoda 的回复:
Quote: 引用 2 楼 Fire_Lord 的回复:

[/code]

感谢,(FBase)child 按照你说的应该是用child的基类部分拷贝构造一个匿名的FBase对象,可是还是不太明白这种转换为什么会有拷贝构造的调用,是标准有规定吗

根据不同的场景调用不同的构造函数:


using namespace std;

class TestClass
{
public:
	TestClass(){ cout << "constructor..." << endl; }

	TestClass(TestClass& b) { cout << "copy constructor..." << endl;}

	TestClass& operator = (const TestClass& b) 
	{ cout << "assignment constructor..." << endl; return *this;}
};

void TestFunc(TestClass c){}

int _tmain(int argc, _TCHAR* argv[])
{
	//调用一般的构造函数
	TestClass obj1;			//constructor

	//创建对象并初始化,调用拷贝构造函数
	TestClass Obj2(obj1);	//copy constructor
	TestClass Obj3 = obj1;	//copy constructor

	//传递参数,产生临时变量,调用拷贝构造函数
	TestFunc(obj1);			//copy constructor

	//赋值操作,调用赋值构造函数
	Obj3 = Obj2;			//assignment constructor

	return 0;
}


1 (FBase)child 肯定产生了临时对象,通过拷贝构造
2 ((FBase)child).Set();这句没有意义,因为这是对临时对象的操作,不会影响child
3 FBase* pBase = (FBase*)&child;是多态
4 FBase* pBase2 = &(FBase)child;是把一个临时FBase对象的指针赋值给pBase2
多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。
引用 5 楼 shenchenman 的回复:

1 (FBase)child 肯定产生了临时对象,通过拷贝构造
2 ((FBase)child).Set();这句没有意义,因为这是对临时对象的操作,不会影响child
3 FBase* pBase = (FBase*)&child;是多态
4 FBase* pBase2 = &(FBase)child;是把一个临时FBase对象的指针赋值给pBase2

肯定产生了临时对象
请教下为什么会产生

引用 6 楼 zhousitiaoda 的回复:

多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。

因为这属于强制类型转换,而不是多太用到的引用或指针的转换。
就像 (int)123.01f

10分
引用 7 楼 zhousitiaoda 的回复:
Quote: 引用 5 楼 shenchenman 的回复:

1 (FBase)child 肯定产生了临时对象,通过拷贝构造
2 ((FBase)child).Set();这句没有意义,因为这是对临时对象的操作,不会影响child
3 FBase* pBase = (FBase*)&child;是多态
4 FBase* pBase2 = &(FBase)child;是把一个临时FBase对象的指针赋值给pBase2

肯定产生了临时对象
请教下为什么会产生

既然有类型转换,当然会产生一个对应转换后型的对象,以供拷贝或其他操作。

引用 8 楼 Fire_Lord 的回复:
Quote: 引用 6 楼 zhousitiaoda 的回复:

多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。

因为这属于强制类型转换,而不是多太用到的引用或指针的转换。
就像 (int)123.01f

你的意思是说,这种强制转换不管是内置类型还是class类型,都会伴随着临时对象的生成?

引用 10 楼 zhousitiaoda 的回复:
Quote: 引用 8 楼 Fire_Lord 的回复:
Quote: 引用 6 楼 zhousitiaoda 的回复:

多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。

因为这属于强制类型转换,而不是多太用到的引用或指针的转换。
就像 (int)123.01f

你的意思是说,这种强制转换不管是内置类型还是class类型,都会伴随着临时对象的生成?

引用 10 楼 zhousitiaoda 的回复:
Quote: 引用 8 楼 Fire_Lord 的回复:
Quote: 引用 6 楼 zhousitiaoda 的回复:

多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。

因为这属于强制类型转换,而不是多太用到的引用或指针的转换。
就像 (int)123.01f

你的意思是说,这种强制转换不管是内置类型还是class类型,都会伴随着临时对象的生成?

你指的内置类型

引用 10 楼 zhousitiaoda 的回复:
Quote: 引用 8 楼 Fire_Lord 的回复:
Quote: 引用 6 楼 zhousitiaoda 的回复:

多谢,额,我的意思并不是说为什么调用的是拷贝构造而不是构造,我想问的是为什么这种转换会有对象的生成。

因为这属于强制类型转换,而不是多太用到的引用或指针的转换。
就像 (int)123.01f

你的意思是说,这种强制转换不管是内置类型还是class类型,都会伴随着临时对象的生成?

不是。
临时对象建立一个没有命名的非堆对象会产生临时对象。这种未命名的对象通常在三种条件下产生:为了使函数成功调用而进行隐式类型转换时候、传递函数参数和函数返回对象时候。
临时对象是代码中看不到的,但是实际程序中确实存在的对象。临时对象是可以被编译器感知的。
内置类型不存在对象,只是变量

感谢2位的回答,过几天再结,看还有没有不同的意见的。
引用 12 楼 shenchenman 的回复:

这种未命名的对象通常在三种条件下产生:为了使函数成功调用而进行隐式类型转换时候、传递函数参数和函数返回对象时候。
[

可是这里的强制转换不属于这3种条件的任何一种。

50分
这句 (FBase)child 叫 explicit type conversion (cast notation)。
标准 5.4 定义了其行为,对主楼的用例,该语句等同与 static_cast<FBase>(child),后者的行为在 5.2.9/4 定义:
Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
所以 ((FBase)child).Set(); 就是

FBase e(child); // copy construction
e.Set();

第一句就是复制构造发生的点。

引用 15 楼 ri_aje 的回复:

这句 (FBase)child 叫 explicit type conversion (cast notation)。
标准 5.4 定义了其行为,对主楼的用例,该语句等同与 static_cast<FBase>(child),后者的行为在 5.2.9/4 定义:
Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
所以 ((FBase)child).Set(); 就是

FBase e(child); // copy construction
e.Set();

第一句就是复制构造发生的点。

多谢指点。。

对于C风格的强制转换,以下两种方式的效果是一样的。
(T)expression    //将expression转型为T类型
T(expression)     //将expression转型为T类型

对于楼主的(FBase)child这样的强制转换,可以完全等同于
FBase(child)
这样再看的话,是不是就很清楚了。
临时变量生成了,发生了slicing!
再补充一句,使用static_cast<T>(child)将产生同样的效果,即也会生成临时基类变量。


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明请教下派生类对象强制转换为基类对象,会不会有临时对象产生?如果有,为什么?
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!