2014-03-04 102 views
2

我有以下类别:这是隐式地调用一个拷贝构造函数吗?

class Player 
{ 
public: 
    Inventory& GetInventory() 
    { 
     return inventory; 
    } 
private: 
    Inventory inventory; 
}; 

class Inventory 
{ 
    // Methods removed for brevity 
private: 
    std::vector<std::string> items; 
}; 

我想要做的就是让代码的用户修改的Player::inventory内容,而不能重新分配给不同的对象。简单的例子:

Player player; 

// OK: I want to able to add items. 
player.GetInventory().AddItem("Item 1"); 

// Not OK: I don't want to be able to assign 
// Player::inventory to a different Inventory. 
Inventory badInventory; 
player.GetInventory() = badInventory; 

我知道我可以通过修改GetInventory()返回Inventory* const做到这一点,但这种情况下是让我怀疑什么,我认为是引用的事实。我相信他们:

  1. 不是对象本身,所以没有地址。
  2. 无法在其生命周期内重新分配。
  3. 声明时必须初始化。

对我说badInventory必须以某种方式被隐式复制。所以我定义了一个拷贝构造函数,希望能记录电话,就像这样:

Inventory(const Inventory& rhs) 
{ 
    std::cout << "Copy ctor." << std::endl; 
} 

但是,这永远不会触发。所以我的问题归结为:这一行发生了什么?

player.GetInventory() = badInventory; 

我在这里失去了一些东西,但我不知道它是什么。

回答

6

该行实际上调用了复制赋值操作符,而不是复制构造函数。这是宣布为

Inventory& operator=(const Inventory&); 

注意player.GetInventory()已经存在对象的功能,所以它不能调用拷贝构造函数,仅仅是因为你没有任何建设。

如果你想禁止被复制库存,删除这些功能:

Inventory(const Inventory&) = delete; 
Inventory& operator=(const Inventory&) = delete; 

或者,如果你的编译器没有C++ 11的支持,声明为private,并没有提供一个定义。

private: 
    Inventory(const Inventory&); 
    Inventory& operator=(const Inventory&); 
+0

感谢您的回答。只是为了澄清,当你说:'请注意,player.GetInventory()是一个已经存在的对象,所以它不能调用复制构造函数,它只适用于复制构造函数,而不适用于复制指定构造函数?另外,这是否意味着我在这里的一般用法是通过使用'Inventory * const GetInventory()'来促进'Player'的封装,假设我只是想阻止重新分配'Player :: inventory',不妨碍复制库存本身? –

+0

@John查看'初始化'与'赋值'。 – 2014-03-04 17:26:15

+0

@remyabel我知道他们之间的区别。我只是没有意识到第二种类型的拷贝构造函数,所以我确信评论中没有错误,只是为了确保。 –

1

在这种scenarion

player.GetInventory() = badInventory; 

有用于类库存的拷贝赋值运算符。

您可以将复制/移动赋值运算符定义为已删除。例如

class Inventory 
{ 
public: 
    Inventory & operator =(const Inventory &) = delete; 
    Inventory & operator =(Inventory &&) = delete; 
    // Methods removed for brevity 
private: 
    std::vector<std::string> items; 
}; 

或者你可以将它们声明为私有成员函数。

虽然在我看来,这将是更好,如果你需要定义所有需要处理矢量作为成员函数,而不是参考了久违的矢量

+0

感谢您的回答,但我没有返回对矢量的引用。 'AddItems'以及其他函数被定义为'Inventory'的成员函数。因此,它们不会将该向量公开为'Inventory'的公共接口的一部分。 –

相关问题