从派生 class 调用的复制构造函数
Copy constructor called from derived class
有人可以解释这里的输出吗? 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? r
在createTreap()
和createTreapPair()
中都是std::make_shared<Treap::Node>
类型,为什么r = std::dynamic_pointer_cast<Node>(root);
在Treap::display()
中把r变成nullptr呢?在 createTreapPair()
?
之后
@IgorTandetnik 已经指出了你代码中的问题。
BinaryTree
copy constructor explicitly slices away Treap::Node
, and creates an instance of BinaryTree::Node
that root holds on to. Then of course dynamic_cast<Treap::Node>(root)
returns nullptr
.
解决这个问题的一种方法是创建一个virtual
成员函数来克隆一个BinaryTree::Node
并在Node
和BinaryTree
的复制构造函数中使用它。
这是您的代码的更新版本:
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";
}
};
有人可以解释这里的输出吗? 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? r
在createTreap()
和createTreapPair()
中都是std::make_shared<Treap::Node>
类型,为什么r = std::dynamic_pointer_cast<Node>(root);
在Treap::display()
中把r变成nullptr呢?在 createTreapPair()
?
@IgorTandetnik 已经指出了你代码中的问题。
BinaryTree
copy constructor explicitly slices awayTreap::Node
, and creates an instance ofBinaryTree::Node
that root holds on to. Then of coursedynamic_cast<Treap::Node>(root)
returnsnullptr
.
解决这个问题的一种方法是创建一个virtual
成员函数来克隆一个BinaryTree::Node
并在Node
和BinaryTree
的复制构造函数中使用它。
这是您的代码的更新版本:
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";
}
};