抱歉这个愚蠢的问题,但我自己也找不到答案,我在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 :(得分:15)
根据OP的后续评论:
DBUserObject用户(3)。它正在加载 其构造函数中的项目。
如果你的意思是DBObject
构造函数(而不是DBUserObject
构造函数),那就是你的问题。虚函数在构造函数中不起作用。构造函数从最小派生(最基础)类运行到最派生(实际类型)类。当一个类的构造函数运行时,该对象只是该类的类型,而不再是派生的。
换句话说,当您创建DBUserObject
时,首先运行QObject
构造函数,并且在该构造函数中,该对象仅为QObect
而已。然后,DBObject
构造函数运行,并且在该构造函数内,该对象仅为DBObject
,仅此而已。最后,DBUserObject
构造函数运行,对象最终为DBUserObject
。
因此,如果您在load()
构造函数内部调用DBObject
,那么该对象在此时仅为DBObject
,因此只有DBObject
版本的加载。这同样适用于任何虚拟功能。
如果您想获得调用DBUserObject
load()
版本的效果,则需要从DBUserObject
构造函数调用它,或者在对象具有之后从类外部调用它已经建成。
更多信息:
答案 1 :(得分:3)
问题很可能不在您提供的代码中。你在切片DBObject
吗?如果将值传递给函数,或者直接存储在容器内(而不是通过指针),则可能发生这种情况。
另一件事是为什么基类中tableName()
不是纯虚拟的?
答案 2 :(得分:2)
你可以使用'pure virtual'函数来确保只能使用子类,因为基类(DbObject)没有表名。
这将强制DbObject的所有实例化(通过继承的类)具有有效的表名
例如:
virtual QString tableName() = 0;
答案 3 :(得分:1)
首先,使用Google阅读C ++中的“对象切片”。在C ++中切片对象很容易(但错误),特别是对于新手:如果按值传递一个对象(通常是错误的)而不是通过引用传递(通常是正确的),则会发生切片,例如,如果您声明了“DBObject”类型的参数(错误)而不是“DbObject&amp;”或“const DbObject&amp;” (右)。
其次,将以下语句添加到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:因此,第三步是通过更改参数类型以通过引用传递来修复这些错误。
答案 4 :(得分:0)
你不应该内联虚函数,因为有些编译器无法很好地处理它。
您应该将DBObject :: tableName()和DBUserObject :: tableName的实现移动到.cpp文件。
答案 5 :(得分:0)
这里你似乎没有做错任何事。你确定你的QString :: arg(...)方法没有问题吗?
明确地调用this-&gt; tableName();看起来像编译器问题。
- 更新 -
实际上你对tableName()的定义应该是
virtual void tableName() const { ... }
确保你的operator = for QString是有序的(const和非const版本),可能是从tableName()返回的QString是一个临时的堆栈,在这种情况下运算符=将被称为......