从派生类中调用复制构造函数

从派生类中调用复制构造函数

问题描述:

有人可以在这里解释输出吗? createTreap()工作正常,并且r不是nullptr,但是createTreapPair()treapPair.first.display(); treapPair.second.display();后离开r == nullptr。为什么?两者有什么区别?这里发生了什么?从派生类中调用复制构造函数

#include <iostream> 
#include <memory> 

class BinaryTree { 
public: 
    class Node { 
     int value; 
     std::shared_ptr<Node> left = nullptr, right = nullptr, parent = nullptr; 
     friend class BinaryTree; friend class Treap; 
    public: 
     Node (int v) : value(v) {} 
     virtual ~Node() = default; 
     Node (const Node&); 
    }; 
    BinaryTree() : root(nullptr) {} 
    BinaryTree (const BinaryTree& other) : root(std::shared_ptr<Node>(new Node(*other.root))) {std::cout << "BinaryTree copy constructor called.\n";} 
    void setRoot (const std::shared_ptr<Node>& node) {root = node;} 
protected: 
    std::shared_ptr<Node> root; 
}; 

BinaryTree::Node::Node (const Node& other) : value(other.value) { 
    std::cout << "Node copy constructor called, value = " << value << '\n'; 
    if (other.left) left = std::shared_ptr<Node>(new Node(*other.left)); 
    if (other.right) right = std::shared_ptr<Node>(new Node(*other.right)); 
} 

class Treap : public BinaryTree { 
public: 
    class Node : public BinaryTree::Node { 
     int priority; 
     friend class Treap; 
    public: 
     Node (int value) : BinaryTree::Node(value), priority(std::rand() % 100) {} 
     Node (const Node& other) : BinaryTree::Node(other), priority(other.priority) {} // Treap::Node copy constructor. 
    }; 
    void display() const { 
     std::shared_ptr<Node> r = std::dynamic_pointer_cast<Node>(root); // Casting from BinaryTree::Node to Treap::Node. 
     std::cout << "r = " << r << '\n'; 
     if (root) std::cout << "Root exists and has value " << root->value << ".\n"; 
    } 
}; 

Treap createTreap() { 
    std::cout << "\n\ncreateTreap() called.\n"; 
    Treap treap; 
    std::shared_ptr<Treap::Node> r = std::make_shared<Treap::Node>(4); 
    treap.setRoot(r); 
    return treap; 
} 

std::pair<Treap, Treap> createTreapPair() { 
    std::cout << "\n\ncreateTreapPair() called.\n"; 
    Treap treap1, treap2; 
    std::shared_ptr<Treap::Node> r = std::make_shared<Treap::Node>(11); 
    treap1.setRoot(r); 
    treap2.setRoot(r); 
    return std::make_pair(treap1, treap2); 
} 

int main() { 
    const Treap treap = createTreap(); 
    treap.display(); // Works fine, r != nullptr. 

    const std::pair<Treap, Treap> treapPair = createTreapPair(); 
    treapPair.first.display(); // r is nullptr! 
    treapPair.second.display(); // r is nullptr! 

    std::cin.get(); 
} 

如何解决上面的代码,这样r不转treapPair.first.display(); treapPair.second.display();后nullptr? rcreateTreap()createTreapPair()中都是std::make_shared<Treap::Node>,那么为什么r = std::dynamic_pointer_cast<Node>(root);Treap::display()中将r转换为nullptr?之后createTreapPair()

+0

变量'treap1'和'treap2'走出去的范围,不是吗? – Chiel

+1

'BinaryTree'拷贝构造函数明确地切掉'Treap :: Node',并且创建'root'保存的'BinaryTree :: Node'的实例。当然''dynamic_cast <:node>(root)'返回'nullptr'。 'createTreap'能够避开拷贝构造函数,但'createTreapPair'不是。 –

+0

@Chiel这就是为什么需要调用复制构造函数的原因。 @Igor所以'Treap :: Node'的拷贝构造函数是不够的?我需要为'Treap'定义一个拷贝构造函数?那么'BinaryTree'拷贝构造函数还没有做什么?那个拷贝构造函数是什么样的? – prestokeys

@IgorTandetnik已经在你的代码中指出了这个问题。

BinaryTree拷贝构造函数明确切片远Treap::Node,并创建一个BinaryTree::Node实例根持有上。当然,dynamic_cast<Treap::Node>(root)返回nullptr。要解决这个问题

一种方法是创建一个virtual成员函数克隆BinaryTree::Node并在NodeBinaryTree拷贝构造函数中使用它。

这里是你的代码的更新版本:

class BinaryTree { 
    public: 
     class Node { 
     int value; 
     std::shared_ptr<Node> left = nullptr, right = nullptr, parent = nullptr; 
     friend class BinaryTree; friend class Treap; 
     public: 
     Node (int v) : value(v) {} 
     virtual ~Node() = default; 
     Node (const Node&); 

     ////////////////////////////// 
     // New code 
     ////////////////////////////// 
     virtual Node* clone() const = 0; 

     }; 
     BinaryTree() : root(nullptr) {} 
     BinaryTree (const BinaryTree& other) : root(nullptr) 
     { 
     ////////////////////////////// 
     // Updated code 
     ////////////////////////////// 
     if (other.root) 
     { 
      root = std::shared_ptr<Node>(other.root->clone()); 
     } 

     std::cout << "BinaryTree copy constructor called.\n"; 
     } 
     void setRoot (const std::shared_ptr<Node>& node) {root = node;} 
    protected: 
     std::shared_ptr<Node> root; 
}; 

BinaryTree::Node::Node (const Node& other) : value(other.value) { 
    std::cout << "Node copy constructor called, value = " << value << '\n'; 

    ////////////////////////////// 
    // Updated code 
    ////////////////////////////// 
    if (other.left) left = std::shared_ptr<Node>(other.left->clone()); 
    if (other.right) right = std::shared_ptr<Node>(other.right->clone()); 
} 

class Treap : public BinaryTree { 
    public: 
     class Node : public BinaryTree::Node { 
     int priority; 
     friend class Treap; 
     public: 
     Node (int value) : BinaryTree::Node(value), priority(std::rand() % 100) {} 
     Node (const Node& other) : BinaryTree::Node(other), priority(other.priority) {} // Treap::Node copy constructor. 

     ////////////////////////////// 
     // New code 
     ////////////////////////////// 
     virtual Node* clone() const 
     { 
      return new Node(*this); 
     } 
     }; 
     void display() const { 
     std::shared_ptr<Node> r = std::dynamic_pointer_cast<Node>(root); // Casting from BinaryTree::Node to Treap::Node. 
     std::cout << "r = " << r.get() << '\n'; 
     if (root) std::cout << "Root exists and has value " << root->value << ".\n"; 
     } 
}; 
+0

谢谢。不能BinaryTree的clone()函数是'virtual Node * clone()const {return new Node(* this);}'和BinaryTree :: Node拷贝构造函数是:'BinaryTree :: Node :: Node(const Node&其他):value(other.value){ \t if(other.left)left = std :: shared_ptr (new Node(* other.left)); \t if(other.right)right = std :: shared_ptr (new Node(* other.right));我也测试过了。当然,你的方式非常好。但我不希望'BinaryTree :: Node'是抽象的。 – prestokeys

+0

@prestokeys,你不能在基类中实现'clone()'。使用您建议的方法将始终切割对象。出于同样的原因,您不能在'BinaryTree :: Node'的拷贝构造函数中使用'left = std :: shared_ptr (new Node(* other.left));'。 –