2010-06-16 63 views
2

对不起,这个愚蠢的问题,但我不能找到自己的答案,我用C太新++ :(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); 

但结果我有一个运行时错误为什么不“配置文件”

+0

你在什么平台上使用什么编译器?如果您将'tableName()'的实现移动到cpp文件中,那么结果是否会发生变化,就像您使用load()一样? – 2010-06-16 12:19:13

+0

1. linux上的gcc和windows上的mingw 2.不改变 – silent 2010-06-16 12:25:56

+0

你是_really_只做两行'DBUserObject user;'后跟'user.load(3);'? – Troubadour 2010-06-16 12:39:53

回答

15

基于业务方案的后续评论:

DBUserObject用户(3)。它正在其构造函数中加载 项目。

如果你的意思是DBObject构造函数(而不是DBUserObject构造函数),那么你的问题。虚函数在构造函数中不起作用。构造函数从派生最少(最基础)的类运行到派生最多(实际类型)的类。当一个类的构造函数运行时,该对象只是该类的类型,并没有更多的派生。

换句话说,当您创建DBUserObject时,首先运行QObject构造函数,并且在该构造函数中,该对象仅为QObect,仅此而已。然后,DBObject构造函数运行,并且在该构造函数中,该对象只是一个DBObject,仅此而已。最后,运行DBUserObject构造函数,最后该对象是DBUserObject

所以,如果你load()DBObject构造函数里面,对象是唯一在该点DBObject,因此只有在DBObject版本负荷。这适用于任何虚拟功能。

如果您想要调用DBUserObject版本load()的效果,则需要在DBUserObject构造函数中调用该构造函数,或者在构造该对象后从类外部调用该构造函数。

的更多信息:

+0

+1实际上发现问题:虚拟与构造函数。 – 2010-06-16 12:51:34

+0

哇。它的工作原理,感谢您的帮助和耐心。 对不起,我没有预料到构造函数使用的问题原因:) – silent 2010-06-16 12:53:33

+1

+1不仅对于解决方案,而且对你所做的猜测也是如此。 :) – liaK 2010-06-16 16:41:49

0

你不应该内联虚函数,因为有些编译器不能很好地处理它。

您应该将DBObject :: tableName()和DBUserObject :: tableName的实现移动到.cpp文件。

+0

相同的结果:( – silent 2010-06-16 12:26:33

0

你在这里似乎没有做错任何事。你确定问题不在你的QString :: arg(...)方法中吗?

显式调用this-> tableName();看起来像一个编译器问题。

- 更新 -

其实你的表名()的定义应该是

virtual void tableName() const { ... } 

确保您的运营商=为QString的是为了(包括一个const和非const版本) ,可能是从tableName()返回的QString是通过堆栈临时的,在这种情况下operator =将被调用...

+0

试图做的只是QString tb = tableName() - 相同的空字符串 – silent 2010-06-16 12:28:02

+0

“this”不起作用,“const”也不起作用:( – silent 2010-06-16 12:37:31

+0

请确保基础和派生我认为你需要看看QString类 – 2010-06-16 12:39:27

3

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

另一件事是为什么在基类中tableName()不是纯虚拟的?

+0

什么是纯虚函数?再次抱歉 - 我太新了C++ – silent 2010-06-16 12:31:01

+0

@silent:纯虚函数该函数没有定义一个主体,这使得类“抽象”(尽管这不是C++关键字),它的意思是,该类不能被实例化,它只是用作其他类的模板派生的,然后将提供一个纯虚函数的主体。它是这样定义的:virtual void func()= 0; – PeterK 2010-06-16 12:45:20

+0

谢谢你的解释,我会记住它 – silent 2010-06-16 13:30:48

2

由于基类(DbObject)没有表名,因此可以使用'纯虚函数'来确保只能使用子类。

这将迫使DBOBJECT的所有实例(通过继承的类)有一个有效表名

例如: virtual QString tableName() = 0;

+0

我在QString上得到运行时错误tb = tableName(); – silent 2010-06-16 12:34:50

+0

然后你的问题是你实际上并没有重写'DBUserObject'类中的'tableName'函数。你确定*你上面发布的内容是你的代码的精确反映吗?确保你没有拼错'tableName'或者添加一个'const'限定符,或者改变返回类型,或者那种类型的东西。 – 2010-06-16 12:42:47

1

首先,使用谷歌阅读有关在C “对象切片” ++。在C++中切片对象很容易(但是是错误的),特别是对于新手来说:如果按值传递对象(通常是错误的)而不是通过引用传递(通常是正确的),则会发生切片,例如,如果声明参数的类型为“DBObject”(错误)而不是“DbObject &”或“const DbObject &”(右)。

二,下列语句添加到您的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&); 
}; 

声明非默认情况下,未实现的复制和分配将导致编译时错误whereveryou尝试按值传递一个DBOBJECT:所以,第三步骤是通过将参数类型更改为通过引用传递来修复这些错误。

+0

谢谢你切片和引用,我今天会检查它 – silent 2010-06-16 13:01:27