none
c++拷贝构造函数的疑惑 RRS feed

  • 问题

  • 如下伪码:又一个类MyClass
    Class MyClass
    {

    }

    在使用的时候是这样
    MyClass A;
    MyClass B = A;//这里实际上是会调用拷贝构造函数,这没有问题。

    但如果是这样使用
    MyClass A,B;
    B = A;//这里就不会在调用拷贝构造函数了,请问这是为什么??

    2:如果一个类有多个自定义的构造函数会后什么后果?
    如:
    MyClass(const MyClass& myclass);/*拷贝构造函数*/
    MyClass(MyClass& myclass);/*拷贝构造函数*/

    谢谢大家
    2010年2月19日 9:29

答案

  • 问题一:
    大家都知道只有在创建某个类的实例时,才会自动的调用构造。 第一种写法 MyClass B = A; 在声明了一个MyClass 类型的实例B的同时,同时给B赋值。因此会调用到MyClass 的拷贝构造。 第二种写法: MyClass A,B; // 这一行执行完,B对象就创建成功了,也就是说, 这行代码执行完成后, 系统已经为B调用完成了合适的构造。 B = A; 此时只能去寻找MyClass 是否有合适的运算符重载了。因此,你第二种写法 B = A; 时,不会调用到拷贝构造。

    问题二:
    多个拷贝构造会引发
    Warning    1    warning C4521: 'testClass' : multiple copy constructors specified   编译器警告,但不会导致程序运行出现什么太大问题。系统总是可以找到合适的拷贝构造函数调用。

    比如:
    class testClass
    {
    public:
    	int m_iValueA;
    	int m_ivalueB;
    public:
    	testClass()
    	{
    		m_iValueA = 99;
    		m_ivalueB = 999;
    	}
    
    	testClass(testClass& A)
    	{
    		m_iValueA = A.m_iValueA;
    		m_ivalueB = A.m_ivalueB + 1;
    	}
    	testClass(const testClass& A)
    	{
    		m_iValueA = A.m_iValueA + 1;
    		m_ivalueB = A.m_ivalueB + 1;
    	}
    
    	testClass Me(void) const
    	{
    		return *this;
    	}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	testClass A;
    	testClass B = A.Me();  // 调用const 拷贝构造
    	testClass C = A;       // 调用普通拷贝构造
    
    	printf("ValueA = %d\t ValueB = %d\r\n", B.m_iValueA, B.m_ivalueB);
    	printf("ValueA = %d\t ValueB = %d\r\n", C.m_iValueA, C.m_ivalueB);
    	getchar();
    	return 0;
    }
    • 已标记为答案 vieri122 2010年2月20日 10:56
    2010年2月20日 2:09
    版主
  • 问题一:  一般来说你使用Visual Studio 的C++编译器cl.exe 编译时, 编译器都会给没有拷贝构造的类型偷偷地添加一个拷贝构造函数。这个拷贝构造函数就叫做默认拷贝构造函数。有一篇文章推荐给你:
    http://blog.chinaunix.net/u/24474/showart_183433.html

         也就是说如果你没有在testClass 类型中显式的声明一个拷贝构造函数,编译器在编译时就会给你偷偷添加一个,当执行testClass B = A; 时调用的就是这个默认拷贝构造函数。 另外cl.exe 现在也支持结构体和类之间进行赋值,也就是直接执行 B = A; 编译器也是支持的,当然推荐的方式是你自己重载“=” 运算符(operator =)。因为这只是一个cl.exe 编译器的特性,不能担保其他C++编译器如gcc 也支持这个特性(不好意思,我没有查过gcc 是否真的支持)。

    拷贝构造都是成员传值的,一般不传递引用。

    问题二,我的代码很清楚啊,你放到你的Visual Studio 跑一下就看到了。

    按照你的意思,我创建的testClass 有两个拷贝构造函数,一个是以testClass& 为参数的,另一个是const testClass& 为参数的。 Me() 方法是为了返回一个const testClass 类型的对象。当执行testClass B = A.Me(); 时,实际上传入的是const testClass& 类型,因此调用const testClass& 类型的拷贝构造;当执行testClass C = A; 时,调用的就是testClass 类型的拷贝构造。

    同时编译器还会告诉你一个拷贝构造函数太多的警告。
    • 已标记为答案 vieri122 2010年2月20日 10:56
    2010年2月20日 6:37
    版主

全部回复

  • 问题一:
    大家都知道只有在创建某个类的实例时,才会自动的调用构造。 第一种写法 MyClass B = A; 在声明了一个MyClass 类型的实例B的同时,同时给B赋值。因此会调用到MyClass 的拷贝构造。 第二种写法: MyClass A,B; // 这一行执行完,B对象就创建成功了,也就是说, 这行代码执行完成后, 系统已经为B调用完成了合适的构造。 B = A; 此时只能去寻找MyClass 是否有合适的运算符重载了。因此,你第二种写法 B = A; 时,不会调用到拷贝构造。

    问题二:
    多个拷贝构造会引发
    Warning    1    warning C4521: 'testClass' : multiple copy constructors specified   编译器警告,但不会导致程序运行出现什么太大问题。系统总是可以找到合适的拷贝构造函数调用。

    比如:
    class testClass
    {
    public:
    	int m_iValueA;
    	int m_ivalueB;
    public:
    	testClass()
    	{
    		m_iValueA = 99;
    		m_ivalueB = 999;
    	}
    
    	testClass(testClass& A)
    	{
    		m_iValueA = A.m_iValueA;
    		m_ivalueB = A.m_ivalueB + 1;
    	}
    	testClass(const testClass& A)
    	{
    		m_iValueA = A.m_iValueA + 1;
    		m_ivalueB = A.m_ivalueB + 1;
    	}
    
    	testClass Me(void) const
    	{
    		return *this;
    	}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	testClass A;
    	testClass B = A.Me();  // 调用const 拷贝构造
    	testClass C = A;       // 调用普通拷贝构造
    
    	printf("ValueA = %d\t ValueB = %d\r\n", B.m_iValueA, B.m_ivalueB);
    	printf("ValueA = %d\t ValueB = %d\r\n", C.m_iValueA, C.m_ivalueB);
    	getchar();
    	return 0;
    }
    • 已标记为答案 vieri122 2010年2月20日 10:56
    2010年2月20日 2:09
    版主
  • 你好,
    对于第一个问题,如果是去找“=”的重载运算,如果我没有显示的重载“=”,对象里面的成员是会怎么样复制,都是拷贝?还是传引用过去?
    对于第二个问题看了代码后,没太看明白,能稍微从纯理论上解释一下吗?谢谢
    • 已编辑 vieri122 2010年2月20日 5:07
    2010年2月20日 5:05
  • 问题一:  一般来说你使用Visual Studio 的C++编译器cl.exe 编译时, 编译器都会给没有拷贝构造的类型偷偷地添加一个拷贝构造函数。这个拷贝构造函数就叫做默认拷贝构造函数。有一篇文章推荐给你:
    http://blog.chinaunix.net/u/24474/showart_183433.html

         也就是说如果你没有在testClass 类型中显式的声明一个拷贝构造函数,编译器在编译时就会给你偷偷添加一个,当执行testClass B = A; 时调用的就是这个默认拷贝构造函数。 另外cl.exe 现在也支持结构体和类之间进行赋值,也就是直接执行 B = A; 编译器也是支持的,当然推荐的方式是你自己重载“=” 运算符(operator =)。因为这只是一个cl.exe 编译器的特性,不能担保其他C++编译器如gcc 也支持这个特性(不好意思,我没有查过gcc 是否真的支持)。

    拷贝构造都是成员传值的,一般不传递引用。

    问题二,我的代码很清楚啊,你放到你的Visual Studio 跑一下就看到了。

    按照你的意思,我创建的testClass 有两个拷贝构造函数,一个是以testClass& 为参数的,另一个是const testClass& 为参数的。 Me() 方法是为了返回一个const testClass 类型的对象。当执行testClass B = A.Me(); 时,实际上传入的是const testClass& 类型,因此调用const testClass& 类型的拷贝构造;当执行testClass C = A; 时,调用的就是testClass 类型的拷贝构造。

    同时编译器还会告诉你一个拷贝构造函数太多的警告。
    • 已标记为答案 vieri122 2010年2月20日 10:56
    2010年2月20日 6:37
    版主
  • 多谢,那么对象之间的赋值也是值传递吗?
    向这样。
    MyClass A,B;
    A = B;
    2010年2月20日 11:06
  • 默认行为当然是传值的,如果你重载了“=” 运算符,那就是重载"=" 函数定义的行为了。
    2010年2月20日 12:34
    版主
  • 如果我的类里面有一个成员变量是一个对象,那么这个变量的赋值是如何传递的,也是传值吗?
    2010年2月21日 4:28