如何正确使用复制构造函数

时间:2016-04-14 07:27:19

标签: c++ constructor

我无法理解如何调用/创建复制构造函数。我的问题是否在于我如何在主要调用此问题?或者是否有某种方法需要在Animal.cpp中完成。

如果这样做,我是否可以使用Animal作为基类调用派生类的复制构造函数?

Animal.cpp

#include "Animal.h"

using namespace std;

Animal::Animal()
{

}

Animal::Animal(string s, string c,string a, string d)
{
    species = s;
    classification = c;
    animal = a;
    desc = d;

}

Animal::Animal(const Animal &obj)
{
   //What should be placed in here?
}

Main.cpp的

#include <string>
#include <iostream>
#include "Animal.h"


using namespace std;

int main(){



    Animal *elephant = new Animal("Straight-Tusked","Mammal","Elephant","Grazer");

    Animal *elephant2 = new Animal(*elephant);

}

2 个答案:

答案 0 :(得分:3)

在C ++中,如果可能,请始终使用成员初始化:

Animal::Animal(const string &s, const string &c,const string &a, const string &d)
   : species(s), classification(c), animal(a), desc(d)
{
}

还要注意const-reference的显式传递。如果传递string s,则会获得参数的隐式副本。编译器可能copy-elides这个,所以你不会看到任何差异,但是省略是一种可能会或可能不会发生的优化。

对于复制构造函数,从我们从Animal类看到的内容,你可能想要这样的东西:

Animal::Animal(const Animal &obj)
   : species(obj.species)
   , classification(obj.classification)
   , animal(obj.animal)
   , desc(obj.description)
{
}

复制构造函数应通过为obj分配适当的值来复制*this。请注意,上面也是默认的自动生成的复制构造函数(如果不存在其他字段)。

因为上面与默认的复制构造函数基本相同,所以在C ++ 11及更高版本中,您可以告诉编译器显式生成default copy constructor

class Animal {
    Animal(const Animal &) = default;
};

正如rule-of-three(现在的五条规则)那样,您可能还需要一个复制赋值运算符。

最后,当你在某处new时,你需要delete该对象。 C ++不执行(内置)引用计数,也没有垃圾收集器。如果忘记delete new d对象,则会发生内存泄漏。

正如评论中所指出的那样,完全可以通过声明变量来声明Animal对象

Animal a(
    "Hippopotamus",
    "Mammalia",
    "Hippopotamus",
    "from the movie"
);

当程序离开当前作用域时,将自动清除(及其析构函数)。

答案 1 :(得分:1)

虽然有一个公认的答案,我想我会在你的代码中解决你的评论

//What should be placed in here?

复制构造函数正如它的名称所描述的那样。它是一个从同一类型的另一个对象构造对象的函数。所以简短的回答是,复制构造函数中的代码是创建新对象实例的代码,使用现有实例作为构造源。

如果您自己不提供复制构造函数,编译器会创建一个复制构造函数。在编译器的复制构造函数中,实例被按位复制&#39;,这意味着该类的所有数据成员都是逐位复制的。

如果您的一个或多个数据成员是指针,则会出现问题。在按位复制中,复制实例的指针将指向与复制对象相同的对象。复制对象时,您可能希望复制构造它指向的对象。这是提供自己的拷贝构造函数的原因之一。

例如:

class Foo
{
public:
     int a;
     int b;

     Foo() : a(0), b(0) {}
     Foo(int ain, int bin) : a(ain), b(bin) {}
     ~Foo() {}
}
class Bar
{
     double z;
     Foo* foo;
public:
     Bar() : z(0) , foo(new Foo) {}
     Bar(double zin, Foo* fooin) : z(zin), foo(fooin) {}
     // Copy constructor below
     Bar(const Bar &rhs) : z(rhs.z) , foo(new Foo(rhs.foo->a, rhs.foo->b)) {}
}

Bar的复制构造函数也将构造一个新的Foo对象并指向它。 请注意,Bar的复制构造函数也可以这样完成:

Bar(const Bar &rhs) : z(rhs.z) , foo(new Foo((const Foo&)*(rhs.foo))) {}

将使用编译器的Foo默认复制构造函数。

虽然首选成员初始值设定项,但记住构造函数是函数是有用的,因此您可以使用 this 指针从复制构造函数中调用任何其他构造函数,如下所示:

Animal::Animal(const Animal &obj)
{
    this->Animal(obj.s, obj.c, obj.a, obj.d);
}

请注意,以下操作无效:

Animal::Animal(const Animal &obj)
{
    Animal(obj.s, obj.c, obj.a, obj.d);
}

因为它将被视为表达式并创建一个匿名对象,而不是对构造函数的函数调用(至少在我的编译器上)。