代码之家  ›  专栏  ›  技术社区  ›  silent

C++与虚拟方法重写

  •  2
  • silent  · 技术社区  · 14 年前

    很抱歉这个愚蠢的问题,但是我自己找不到答案,我在C++中太新了:

    class DBObject : public QObject
    {
        ...
    protected:
        virtual QString tableName() = 0;
    };
    
    class DBUserObject : public DBObject
    {
        ...
    protected:
        virtual QString tableName()  { return "profiles"; };
    };
    

    我的父代码是:

    DBObject::DBObject(quint32 id)
        : QObject(0)
    {
        ...    
    
        if (id != 0)
            load(id);
    }
    
    bool DBObject::load(quint32 id)
    {
        QString query = QString("select %1 from %2 where id = :id")
            .arg(fieldList().join(","))
            .arg(tableName());              <--- here is trouble
        ...
    }
    

    所以我想执行:

    DBUserObject user(3);
    

    但结果我有一个运行时错误。为什么不“个人资料”?

    6 回复  |  直到 14 年前
        1
  •  15
  •   Tyler McHenry    14 年前

    根据OP的后续评论:

    dbuserobject用户(3)。它正在装载 其构造函数中的项。

    如果你是说 DBObject 建造师(而不是 DBUserObject 构造器),那就是你的问题。虚拟函数在构造函数内部不工作。构造函数从派生最少(最基本)的类运行到派生最多(实际类型)的类。当类的构造函数运行时,对象仅为该类的类型,而不是派生的。

    换句话说,当你创建一个 dBUS对象 ,首先 QObject 构造函数运行,在该构造函数内,对象仅是 QObect 再也没有了。然后, 数据块 构造函数运行,在该构造函数内,对象仅是 数据块 再也没有了。最后, dBUS对象 构造函数运行,对象最终是 dBUS对象 .

    所以如果你打电话 load() 里面 数据块 构造函数,对象只是 数据块 在这一点上,只有 数据块 加载版本。这同样适用于任何虚拟函数。

    如果您想获得调用 dBUS对象 版本 加载() ,您需要从 dBUS对象 构造函数,或在对象被构造后从类外部调用。

    更多信息:

        2
  •  3
  •   David Rodríguez - dribeas    14 年前

    问题很可能不在您提供的代码中。你在切 DBObject S?如果将旁路值传递到函数中,或者直接存储在容器中(而不是通过指针),则可能发生这种情况。

    另一件事是为什么 tableName() 不是纯虚拟的吗?

        3
  •  2
  •   ianmac45    14 年前

    可以使用“pure virtual”函数来确保只能使用子类,因为基类(dbobject)没有表名。

    这将强制dbobject的所有实例化(通过继承的类)具有 有效的 表名

    例子: virtual QString tableName() = 0;

        4
  •  1
  •   ChrisW    14 年前

    首先,使用谷歌来读取C++中的“对象切片”。在C++中对对象进行切片是很容易的(但是错误的),特别是对于新手:如果按值传递一个对象(通常是错误的)而不是通过引用(通常是正确的),则发生切片,例如,如果声明一个“DBOBEKIT”(错误)类型的参数,而不是“DBOBKEDATP”和“const DBOBEDATA和”(右)。

    其次,将以下语句添加到DBObject类中:

    class DBObject : public QObject 
    { 
        ... 
    protected: 
        virtual QString tableName()  { return ""; }; 
    private:
        //non-default, unimplemented copy ctor and assignment operator
        DBObject(const DBObject&);
        DBObject& operator=(const DBObject&);
    }; 
    

    声明非默认的、未实现的复制和分配将导致编译时错误,在这种情况下,您试图按值传递一个dbobject:因此,第三步是通过将参数类型改为按引用传递来修复这些错误。

        5
  •  0
  •   Philippe Leybaert    14 年前

    您不应该内联虚拟函数,因为有些编译器不能很好地处理这个问题。

    您应该将dbobject::tablename()和dbuserobject::tablename的实现移动到.cpp文件中。

        6
  •  0
  •   Adrian Regan    14 年前

    你在这里好像没做错什么。您确定问题不在qString::arg(…)方法中吗?

    显式调用此->tablename();看起来像编译器问题。

    --更新——

    实际上,TableName()的定义应该是

    virtual void tableName() const { ... }
    

    确保您的qstring的operator=for顺序正确(const和non-const版本),可能是从tablename()返回的qstring是通过堆栈的临时字符串,在这种情况下,将调用operator=