重载运算符[]多态性

Overloading operator [] polymorphism

本文关键字:多态性 运算符 重载      更新时间:2023-10-16
class Base
{
protected:
    string m_Name;
public:
    virtual string Name() { return m_Name; }
    virtual string Type() = 0;
    virtual bool isEqual(Base* rhs) = 0 ;
};

我有一个抽象类Base。我的代码中的不同类继承自这个基类。我将这些对象存储在一个容器(Base的指针向量(中

struct Container
{
    vector<Base*> vec;
    int Count() { return vec.size(); }
    Base* operator[](int i)
    {
        if (i<=0) throw anexception;
        if (i>=vec.size()) throw anexception;
        return vec[i];
    }
};

我重载了运算符[],但只返回了一个指针。有没有一种方法可以让我返回对象vec[I](它是从Base继承的类型(?

如果您希望返回vec[i]:指向的对象,您可以简单地返回一个引用

Base& operator[](int i)
{
    if (i<=0) throw anexception;
    if (i>=vec.size()) throw anexception;
    return *vec[i];
}

但是,在不知道派生类型的情况下,不能返回对象的副本,因为这需要从旧对象构造一个新的Base,而这是不可能的,因为Base是抽象的。

您不应该这样做。

返回类的实例意味着您需要调用复制或移动构造函数。如果您这样做了,那么您将调用基类的复制构造函数。由于基类不知道派生类,因此返回的副本将是派生类的sliced版本。

这意味着,如果派生类具有基类中不存在的变量,则它们将被忽略。更不用说虚拟函数将是基类的函数。

你可以返回一个引用,但我看不出它会比返回一个指针更好。如果你不小心使用引用,你肯定会接触到切片。

您可以编写一个函数来指定所需的类型:

struct Container
{
    ...
    template<typename T>
    T* at(int i)
    {
        ...
        return dynamic_cast<T*>(vec[i]);
    }
};
Container c;
Derived1* d = c.at<Derived1>(3);

如果对象确实是指定类型的,则返回一个有效指针,否则返回一个空指针。

但是,您可以而不是使用operator[]执行此操作。


通常,通过指向基类的指针访问的多态对象的类型在运行时是未知的。从基类到类型派生类的唯一方法是使用switch语句的形式来处理所有可能的派生类:

Base* p = ...;
if(dynamic_cast<Derived1*>(p)) { ... }
else if(dynamic_cast<Derived2*>(p)) { ... }
else if(dynamic_cast<Derived3*>(p)) { ... }
else { ERROR }

这当然是你想要避免的事情。