多态性产生奇怪的行为
Polymorphism produces odd behaviour
我有一个矢量包装器 class 旨在简化多态性:
class Shape
{
public:
Shape(string Name) : name(Name) {}
virtual ~Shape() = default;
string name;
private:
};
class Point : public Shape
{
public:
Point(string Name, float X, float Y) : Shape(Name), x(X), y(Y) {}
float x = 0.0f;
float y = 0.0f;
private:
};
// A vector wrapper for unique ptrs, simplifies polymorphism
template <typename T>
class Vector_UniquePtrs {
public:
// Constructor with no parameters
Vector_UniquePtrs() = default;
// Constructor with initialiser list
Vector_UniquePtrs(std::initializer_list<T> items)
{
m_Items.reserve(items.size());
// fill `m_Items` from the initializer list by creating a unique_ptr from each element
std::transform(items.begin(), items.end(), std::back_inserter(m_Items), [](const T& item) {
return std::make_unique<T>(item);
});
};
// Adds a Polymorphic Item (and returns a raw ptr to it)
// usage: v.Add<sub_class>()
template <class U, class... Args>
T& Add(Args&&... args) {
// Forward args to make_unique
m_Items.emplace_back(std::make_unique<U>(std::forward<Args>(args)...));
// Return a reference
return *m_Items.back();
}
// Adds an Item (and returns a raw ptr to it)
// usage: v.Add() (equivelent to v.Add<base_class>())
template <class... Args>
T& Add(Args&&... args) {
// Forward to Add<U>
return Add<T>(std::forward<Args>(args)...);
}
// Remove item from vector
void Remove(size_t index) {
Assert_IsValid(index);
m_Items.erase(std::next(m_Items.begin(), index));
}
// Access item in vector
T& operator[](size_t index) { Assert_IsValid(index); return *m_Items[index]; } // non-const
const T& operator[](size_t index) const { Assert_IsValid(index); return *m_Items[index]; } // const
// Swaps items[n] and items[n_Next]
void ItemSwap(size_t n, size_t n_Next) {
Assert_IsValid(n);
Assert_IsValid(n_Next);
std::swap(m_Items[n], m_Items[n_Next]);
}
// Gets the number of elements in the vector
size_t Size() const { return m_Items.size(); }
protected:
// The container
std::vector<std::unique_ptr<T>> m_Items;
// Validity function
void Assert_IsValid(int index) { assert(index > -1 && index < (int)Size()); }
};
但是当调用以下内容时:
Vector_UniquePtrs<Shape> v;
v.Add<Point>("A", 1.0f, 10.0f);
Shape& ref = v[0];
v.Add<Point>("B", 2.0f, 20.0f);
ref = v[1];
Point& pt1 = dynamic_cast<Point&>(ref);
Point& pt2 = dynamic_cast<Point&>(v[1]);
cout << pt1.name << ": " << pt1.x << ", " << pt1.y << endl;
cout << pt2.name << ": " << pt2.x << ", " << pt2.y << endl;
输出是:
乙: 1, 10
乙: 2, 20
引用仍然在某种程度上 'thinking' 它正在查看继承变量的 v[0] 和基本变量的 v[1]。有人可以解释发生了什么以及我应该怎么做即将解决这个问题?
谢谢!
您不能重新分配参考。 ref = v[1]
将 v[1]
的值复制到 ref
引用的对象中。由于编译器只知道 ref
是一个 Shape
,它调用 Shape
的赋值运算符,因此只复制 Shape
成员,Point
中的成员保持不变.
如果您需要更改引用指向的内容,那么您可能需要改用指针。
如果您希望赋值以多态方式工作,那么您需要添加一个虚拟方法来为您完成这项工作。
我有一个矢量包装器 class 旨在简化多态性:
class Shape
{
public:
Shape(string Name) : name(Name) {}
virtual ~Shape() = default;
string name;
private:
};
class Point : public Shape
{
public:
Point(string Name, float X, float Y) : Shape(Name), x(X), y(Y) {}
float x = 0.0f;
float y = 0.0f;
private:
};
// A vector wrapper for unique ptrs, simplifies polymorphism
template <typename T>
class Vector_UniquePtrs {
public:
// Constructor with no parameters
Vector_UniquePtrs() = default;
// Constructor with initialiser list
Vector_UniquePtrs(std::initializer_list<T> items)
{
m_Items.reserve(items.size());
// fill `m_Items` from the initializer list by creating a unique_ptr from each element
std::transform(items.begin(), items.end(), std::back_inserter(m_Items), [](const T& item) {
return std::make_unique<T>(item);
});
};
// Adds a Polymorphic Item (and returns a raw ptr to it)
// usage: v.Add<sub_class>()
template <class U, class... Args>
T& Add(Args&&... args) {
// Forward args to make_unique
m_Items.emplace_back(std::make_unique<U>(std::forward<Args>(args)...));
// Return a reference
return *m_Items.back();
}
// Adds an Item (and returns a raw ptr to it)
// usage: v.Add() (equivelent to v.Add<base_class>())
template <class... Args>
T& Add(Args&&... args) {
// Forward to Add<U>
return Add<T>(std::forward<Args>(args)...);
}
// Remove item from vector
void Remove(size_t index) {
Assert_IsValid(index);
m_Items.erase(std::next(m_Items.begin(), index));
}
// Access item in vector
T& operator[](size_t index) { Assert_IsValid(index); return *m_Items[index]; } // non-const
const T& operator[](size_t index) const { Assert_IsValid(index); return *m_Items[index]; } // const
// Swaps items[n] and items[n_Next]
void ItemSwap(size_t n, size_t n_Next) {
Assert_IsValid(n);
Assert_IsValid(n_Next);
std::swap(m_Items[n], m_Items[n_Next]);
}
// Gets the number of elements in the vector
size_t Size() const { return m_Items.size(); }
protected:
// The container
std::vector<std::unique_ptr<T>> m_Items;
// Validity function
void Assert_IsValid(int index) { assert(index > -1 && index < (int)Size()); }
};
但是当调用以下内容时:
Vector_UniquePtrs<Shape> v;
v.Add<Point>("A", 1.0f, 10.0f);
Shape& ref = v[0];
v.Add<Point>("B", 2.0f, 20.0f);
ref = v[1];
Point& pt1 = dynamic_cast<Point&>(ref);
Point& pt2 = dynamic_cast<Point&>(v[1]);
cout << pt1.name << ": " << pt1.x << ", " << pt1.y << endl;
cout << pt2.name << ": " << pt2.x << ", " << pt2.y << endl;
输出是: 乙: 1, 10 乙: 2, 20
引用仍然在某种程度上 'thinking' 它正在查看继承变量的 v[0] 和基本变量的 v[1]。有人可以解释发生了什么以及我应该怎么做即将解决这个问题?
谢谢!
您不能重新分配参考。 ref = v[1]
将 v[1]
的值复制到 ref
引用的对象中。由于编译器只知道 ref
是一个 Shape
,它调用 Shape
的赋值运算符,因此只复制 Shape
成员,Point
中的成员保持不变.
如果您需要更改引用指向的内容,那么您可能需要改用指针。
如果您希望赋值以多态方式工作,那么您需要添加一个虚拟方法来为您完成这项工作。