2010-06-16 131 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