简体   繁体   English

C ++和虚方法覆盖

[英]C++ and virtual methods overriding

Sorry for this stupid question, but I can't find an answer by myself, I'm too new in C++ :( 抱歉这个愚蠢的问题,但我自己找不到答案,我在C ++中太新了:(

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

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

And I have this code in parent: 我在父母中有这个代码:

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
    ...
}

So I'm trying to execute: 所以我正在尝试执行:

DBUserObject user(3);

But in result I have a runtime error. 但结果我有一个运行时错误。 Why not "profiles"? 为什么不“个人资料”?

Based on the OP's followup comment: 根据OP的后续评论:

DBUserObject user(3). DBUserObject用户(3)。 It is loading item in its constructor. 它是在其构造函数中加载项。

If you mean the DBObject constructor (and not the DBUserObject constructor), then there's your problem. 如果你的意思是DBObject构造函数(而不是DBUserObject构造函数),那就是你的问题。 Virtual functions do not work inside constructors. 虚函数在构造函数中不起作用。 Constructors run from the least-derived (most base) class to the most-derived (actual type) class. 构造函数从最小派生(最基础)类运行到最派生(实际类型)类。 When a class' constructor runs, the object is only of that class' type, and nothing more derived. 当一个类的构造函数运行时,该对象只是该类的类型,而不再是派生的。

In other words, when you create a DBUserObject , first the QObject constructor runs, and inside that constructor the object is only a QObect and nothing more. 换句话说,当您创建DBUserObject ,首先运行QObject构造函数,并且在该构造函数中,该对象仅是QObect而已。 Then, the DBObject constructor runs, and inside that constructor the object is only a DBObject and nothing more. 然后, DBObject构造函数运行,并且在该构造函数内,该对象只是一个DBObject ,仅此而已。 Finally, the DBUserObject constructor runs and the object is finally a DBUserObject . 最后, DBUserObject构造函数运行,对象最终是一个DBUserObject

So if you call load() inside of the DBObject constructor, the object is only a DBObject at that point and so has only the DBObject version of load. 因此,如果在DBObject构造函数中调用load() ,则该对象在此时只是一个DBObject ,因此只有DBObject版本的load。 This applies similarly for any virtual function. 这适用于任何虚拟功能。

If you want to get the effect of calling the DBUserObject version of load() , you will need to call it from the DBUserObject constructor, or from outside the class after the object has been constructed. 如果要获得调用load()DBUserObject版本的效果,则需要在构造对象之后从DBUserObject构造函数或类外部调用它。

More information: 更多信息:

The problem is most probably not in the code you provided. 问题很可能不在您提供的代码中。 Are you slicing the DBObject s? 你在切片DBObject吗? That could happen if you pass by value into a function, or if you store inside a container directly (not through a pointer). 如果将值传递给函数,或者直接存储在容器内(而不是通过指针),则可能会发生这种情况。

Another thing is why is the tableName() not pure-virtual in your base class? 另一件事是为什么tableName()在你的基类中不是纯虚拟的?

you could use a 'pure virtual' function to make sure that only subclasses can be used, since the base class (DbObject) doesn't have a table name. 你可以使用'pure virtual'函数来确保只能使用子类,因为基类(DbObject)没有表名。

this would force all instantiations of DbObject (through the inherited classes) to have a valid table name 这将强制DbObject的所有实例化(通过继承的类)具有有效的表名

example: virtual QString tableName() = 0; 示例: virtual QString tableName() = 0;

First, use Google to read about "object slicing" in C++. 首先,使用Google阅读C ++中的“对象切片”。 It's easy (but wrong) to slice an object in C++, especially for novices: slicing happens if you pass an object by value (which is usually wrong) instead of passing by reference (which is usually right), for example if you declare a parameter of type "DBObject" (wrong) instead of "DbObject&" or "const DbObject&" (right). 在C ++中切片对象很容易(但错误),特别是对于新手:如果按值传递一个对象(通常是错误的)而不是通过引用传递(通常是正确的),就会发生切片,例如,如果你声明一个“DBObject”类型的参数(错误)而不是“DbObject&”或“const DbObject&”(右)。

Second, add the following statements to your DBObject class: 其次,将以下语句添加到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&);
}; 

Declaring non-default, unimplemented copy and assignment will cause compile-time errors whereveryou try to pass a DBObject by value: so, the third step is to fix these errors by changing the parameter types to pass by reference instead. 声明非默认的,未实现的复制和赋值将导致编译时错误,其中我们尝试按值传递DBObject:因此,第三步是通过更改参数类型以通过引用传递来修复这些错误。

You shouldn't inline virtual functions, because some compilers can't handle that very well. 你不应该内联虚函数,因为有些编译器无法很好地处理它。

You should move the implementation of DBObject::tableName() and DBUserObject::tableName to the .cpp file. 您应该将DBObject :: tableName()和DBUserObject :: tableName的实现移动到.cpp文件。

You don't seem to be doing anything wrong here. 你似乎没有做错任何事情。 Are you sure the problem is not with your QString::arg(...) method? 你确定你的QString :: arg(...)方法没有问题吗?

Explicitly call this->tableName(); 显式调用this-> tableName(); looks like a compiler problem. 看起来像编译器问题。

-- UPDATE -- - 更新 -

Actually your definition of tableName() should be 实际上你的tableName()的定义应该是

virtual void tableName() const { ... }

Make sure that your operator= for QString is in order (both a const and non-const version), it could be that the QString that is returned from tableName() is a temporary via the stack, in which case the operator= will be called... 确保你的operator = for QString是有序的(const和非const版本),可能是从tableName()返回的QString是一个临时的堆栈,在这种情况下operator =将是叫...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM