2015-10-26 127 views
0

有人可以在這裏解釋輸出嗎? 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 (root)'返回'nullptr'。 'createTreap'能夠避開拷貝構造函數,但'createTreapPair'不是。 –

+0

@Chiel這就是爲什麼需要調用複製構造函數的原因。 @Igor所以'Treap :: Node'的拷貝構造函數是不夠的?我需要爲'Treap'定義一個拷貝構造函數?那麼'BinaryTree'拷貝構造函數還沒有做什麼?那個拷貝構造函數是什麼樣的? – prestokeys

回答

1

@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));'。 –

相關問題