【问题标题】:Cannot implement base class with virtual getters that are defined in child classes无法使用子类中定义的虚拟 getter 实现基类
【发布时间】:2019-11-17 17:48:03
【问题描述】:

我有一个叫Object的类,这个类的头是:

class DLL_SPEC Object {
public:
    Object();
    virtual ~Object();

    virtual std::string getString() const;
    virtual void setString(std::string value);

    virtual int getInt() const;
    virtual void setInt(int value);

    virtual double getDouble() const;
    virtual void setDouble(double value);

    virtual bool isType(FieldType type) const;
};

而我的孩子班级如下:

class DLL_SPEC IntObject : public Object {
public:
    IntObject() : value(0) {}
    IntObject(int v) : value(v) {}
    void setInt(int value) override { this->value = value; };
    int getInt() const override { return this->value; };
    bool isType(FieldType type) const override;
private:
    int value;
};

class DLL_SPEC DoubleObject : public Object {
public:
    DoubleObject() : value(0.0) {}
    DoubleObject(double v) : value(v) {}
    void setDouble(double value) override { this->value = value; };
    double getDouble() const override { return this->value; };
    bool isType(FieldType type) const override;

private:
    double value;
};
class DLL_SPEC StringObject : public Object {
public:
    StringObject() : value("") {}
    StringObject(std::string v) : value(v) {}
    void setString(std::string value) override { this->value = value; };
    std::string getString() const override { return value; };
    bool isType(FieldType type) const override;

private:
    std::string value;
};

现在,问题是,我有一个对象数组,我想获得一个 StringObject 的字符串表示形式。

我调用array[0].getString(),尽管对象是StringObject类型,但被调用的方法是基类,我理解。

那么,每当我在基类上调用 getString() 时,我将如何实现它,它会转到 SAME 对象的子对象之一?

我试过用这个方法:

std::string Object::getString() const
{
    return dynamic_cast<StringObject*>(this).getString();
}

但随后我收到一条错误消息,指出我无法丢弃 const 或任何类型限定符,可以通过删除 const 修饰符来修复(我必须根据任务将其保留在那里),但随后我得到另一个说明没有存在合适的构造函数。那么我将如何实现这一点并让这个基类使用子类之一呢?

编辑:添加了一个小示例,该示例进入 Object 类的 getString 方法,而不是 StringObject 类。

int findPersonId(std::string whereName)
{
    Db* db = Db::open("database");
    Table* people = db->openTable("table");
    auto iteratorTable = table->select();

    while (iteratorTable->moveNext())
    {
        for (size_t i = 0; i < table->getFieldCount(); i++)
        {
            if (table->getFields()[i]->getName() == "id")
            {    //this one beneath goes to the base class and not StringObject
                std::string foundRow = iteratorPeople->getRow()[i]->getString(); 
                if (foundRow == whereName)
                {
                    return iteratorTable->getRowId();
                }
            }
        }
    }
    return 0;
}

注意:Table* 是由 Object** 组成的二维数组(包含 StringObject、IntObject、DoubleObject 的数组)。 .getRow() 方法返回由 StringObject 组成的 Object** 数组 ...

我启动进入数组的对象的方式是

Table* table= db->openOrCreateTable("table", 2, userFields); //this creates a 2d array
StringObject* name = new StringObject("Joseph");
IntObject* id = new IntObject(5);

Object** row = combineToRow(id, name);
table->insert(row); //insert an array into 2D array

combineToRow 方法只是到 Object** 的简单转换器。

template<typename A, typename B>
Object** combineToRow(A a, B b) {
    return new Object * [2]{ a, b };
}

【问题讨论】:

  • “我有一个对象数组” 听起来像是问题的根源。动态多态性只能与指针/引用一起使用。 virtual 关键字的全部意义在于在运行时将调用分派给实际的类,这样您就不必自己动手了。
  • @Yksisarvinen 数组实际上是 Object**,每个索引是 StringObject、IntObject 或 DoubleObject。我可以做一个解决方法,只要我想要 array[0] 我调用一个 dynamic_cast ,那么基类的 getString 方法的意义何在?
  • 这并不能解决主要问题或许多设计问题,但您可以通过使用 dynamic_cast&lt;StringObject const *&gt;(this) 来修复 dynamic_cast(您实际上并不需要它)
  • 这种dynamic_cast 什么都做不了。特定的Object 要么是StringObject,要么不是。如果它是StringObject,则StringObject::getString 会覆盖Object 中的那个。如果不是,Object::getString 中的 dynamic_cast 显然会给你NULL,因为这个Object 不是StringObject,并且显示的代码会爆炸。目前尚不清楚您究竟想在这里完成什么。
  • array[0].getString() 不是指针数组的有效语法。而dynamic_cast 是一种难闻的气味,表明类层次结构有问题。您不需要在基类中实现任何此类奇怪的技巧。你能告诉我们minimal reproducible example 类的virtual 方法调用基类方法而不是派生类方法(在派生类对象上)吗?

标签: c++ inheritance base-class


【解决方案1】:

您还没有为您的IntObject 实现getString 方法,并且由于您没有覆盖它,因此您正在调用基本方法。一旦你像这样实现它

class  IntObject : public Object { 
    ...
    virtual std::string getString() const { return std::to_string(value); };
    ...
};

那么你就可以调用它了。

int main(){
    StringObject* name = new StringObject("Joseph");
    IntObject* id = new IntObject(5);

    Object** row =  combineToRow(id, name);    

    std::cout << row[0]->getString() << " " << row[1]->getString();
}
5 Joseph

查看工作版本here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 2017-11-11
    相关资源
    最近更新 更多