多态性产生奇怪的行为

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 中的成员保持不变.

如果您需要更改引用指向的内容,那么您可能需要改用指针。

如果您希望赋值以多态方式工作,那么您需要添加一个虚拟方法来为您完成这项工作。