如何在 C++ 中克隆对象?或者还有其他解决方案吗?

Posted

技术标签:

【中文标题】如何在 C++ 中克隆对象?或者还有其他解决方案吗?【英文标题】:How to clone object in C++ ? Or Is there another solution? 【发布时间】:2012-10-05 20:20:38 【问题描述】:

我编写了一个堆栈和队列实现(基于链表)。有一个堆栈 (bigStack)。例如,我将bigStack 分开(例如:stackAstackB)。我pop() 来自bigStack 的一个节点,我push()stackA。同样,我在stackBpush()。我希望bigStack 不会改变。因此我想克隆bigStack 对象。如何在 C++ 中克隆对象?或者我的问题有其他解决方案吗?

class Stack : public List 
public:
   Stack() 
   Stack(const Stack& rhs) 
   Stack& operator=(const Stack& rhs) ;
    ~Stack() 

    int Top() 
        if (head == NULL) 
            cout << "Error: The stack is empty." << endl;
            return -1;
         else 
            return head->nosu;
        
    

    void Push(int nosu, string adi, string soyadi, string bolumu) 
        InsertNode(0, nosu, adi, soyadi, bolumu);
    

    int Pop() 
        if (head == NULL) 
            cout << "Error: The stack is empty." << endl;
            return -1;
         else 
            int val = head->nosu;
            DeleteNode(val);
            return val;
        
    

    void DisplayStack(void);

;

那么……

Stack copyStack = veriYapilariDersi;
copyStack.DisplayStack();

【问题讨论】:

您只需复制它,这是语言内置的。我认为你还在学习 C++? (另外,C 和 C++ 是不同的语言) 为 Stack 实现一个拷贝构造函数,即 Stack(Stack const&)。 【参考方案1】:

对此的典型解决方案是编写自己的函数来克隆对象。如果您能够提供复制构造函数和复制赋值运算符,这可能是您需要的。

class Foo
 
public:
  Foo();
  Foo(const Foo& rhs)  /* copy construction from rhs*/ 
  Foo& operator=(const Foo& rhs) ;
;

// ...

Foo orig;
Foo copy = orig;  // clones orig if implemented correctly

有时提供显式的clone() 方法是有益的,尤其是对于多态类。

class Interface

public:
  virtual Interface* clone() const = 0;
;

class Foo : public Interface

public:
  Interface* clone() const  return new Foo(*this); 
;

class Bar : public Interface

public:
  Interface* clone() const  return new Bar(*this); 
;


Interface* my_foo = /* somehow construct either a Foo or a Bar */;
Interface* copy = my_foo->clone();

编辑:由于Stack 没有成员变量,所以在复制构造函数或复制赋值运算符中无需从所谓的“右手边”(rhs)初始化Stack 的成员。但是,您仍然需要确保任何基类都有机会初始化它们的成员。

你可以通过调用基类来做到这一点:

Stack(const Stack& rhs) 
: List(rhs)  // calls copy ctor of List class



Stack& operator=(const Stack& rhs) 

  List::operator=(rhs);
  return * this;
;

【讨论】:

@drceng:你必须实际实现这些功能。您上面提供的代码在方法中没有任何作用。我在这里提出的代码实际上只是伪代码。 我很困惑。我编码了几个小时。我没有看到,方法没有做任何事情:) 好的,我明白了。但是如何实现?如何复制施工? Stack真的没有成员变量吗? 但是请注意,即使使用非多态类,通常也不需要提供显式的复制构造函数或复制赋值运算符。隐式(即编译器提供的默认值)构造函数和运算符通常足以做正确的事情。由于这意味着出错的代码更少,因此除非您确实需要,否则您根本不应该实现这些。 @JohnDibling 我在很大程度上同意,但默认值是否提供正确的行为在很大程度上取决于在类“字段”类型中正确使用 RAII。在大量使用原始指针作为字段的代码库中,默认的复制/分配将几乎从不做正确的事情。这是正确使用 RAII 的另一个重要论据,但有时我们会陷入维护不太理想的代码库的困境。【参考方案2】:

如果您的对象不是多态的(并且堆栈实现可能不是),那么根据此处的其他答案,您想要的是复制构造函数。请注意,C++ 中的复制构造和赋值是有区别的;如果你想要这两种行为(并且默认版本不符合你的需要),你必须实现这两个功能。

如果您的对象是多态的,那么切片可能是一个问题,您可能需要跳过一些额外的环节才能进行正确的复制。有时人们使用名为 clone() 的虚拟方法作为多态复制的助手。

最后,请注意,如果您需要替换默认版本,则正确进行复制和分配实际上是相当困难的。通常最好设置您的对象(通过 RAII),以便默认版本的复制/分配执行您希望它们执行的操作。我强烈建议您查看Meyer's Effective C++,尤其是第 10、11、12 项。

【讨论】:

【参考方案3】:

在 C++ 中,复制对象意味着克隆。该语言没有任何特殊的克隆。

按照标准建议,复制后,您应该拥有同一对象的 2 个完全相同的副本。

有 2 种类型的复制:在未初始化的空间上创建对象时的复制构造函数和在设置新状态之前需要释放对象的旧状态(预期有效)的复制运算符。

【讨论】:

但我的对象已初始化。堆栈已满。我想克隆堆栈及其节点。 我在你的课堂上看不到数据字段。目前尚不清楚您的List 是什么。资料不全。通常,您需要复制对象,在基类中调用相同的方法。你的堆栈元素也应该是可复制的。

以上是关于如何在 C++ 中克隆对象?或者还有其他解决方案吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Kotlin 中克隆对象?

如何在 PHP 中克隆对象数组?

如何在 C++ 中跟踪无效指针?

在 C++ Firemonkey 平台中克隆对象

c++ map的key可以是map吗

如何禁止在 C++ 中使用默认构造函数?