2014-06-14 69 views
0

試圖記住基本的C++東西(已經很長時間了),並且正在使用編譯器。我創建了一個簡單的基本/子繼承示例。繼承示例不打印預期結果

我希望下面的輸出

index 0 is 0 
index 1 is 1 
index 2 is 2 

而是得到:

index 0 is 0 
index 1 is 2 
index 2 is 0 

有人能指出什麼顯然是我的一個可憐的錯誤呢?

#include <cstdlib> 
#include <iostream> 

#include <stdio.h> 
#include <string> 
using namespace std; 

class Base 
{ 
public: 
    Base(){x=0;} 
    int x; 
}; 
class Derived : public Base 
{ 
public: 
    Derived() { y=0;} 
    int y; 
}; 

// practicing operator definition syntax 
ostream& operator<<(ostream& ostr, const Base& base) 
{ 
     ostr << base.x << endl; 
     ostr << flush; 
    return ostr; 
} 

void init(Base *b) 
{ 
    for (int i = 0; i<3; i++) 
    { 
     b[i].x=i; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    Derived arr[3]; 
    init(arr); 
    for (int idx = 0; idx< 3; idx++) 
    { 
     cout << "index is " << idx << ' ' << arr[idx] << endl; 
    } 

    return 0; 
} 
+0

你傳遞給init的是什麼? – nwp

+0

顯然是錯誤的東西(見下面的回覆) – frododot

回答

5

數組和多態不能在C++中混用。

DerivedBase對象具有不同的大小,您程序中涉及的任何指針算術將失敗。

您的init方法正在切片Derived對象在Base對象中。下面的賦值有未定義的行爲,它在Derived對象的某處設置了一些字節。

考慮使用std::vector<std::unique_ptr<B>>作爲替代。

此外,您的Base類缺少其虛擬析構函數,稍後會調用更多未定義的行爲。

+1

+1雖然缺乏虛擬析構函數在這裏不是問題。 – juanchopanza

+0

「數組和多態不混合......」。我不知道這一點。由於數組只是一個指向數組中第一個對象的指針,因此這與指出:Base * b = new Derived [3];啊....你們都是對的。感謝您喚醒已死的腦細胞! :-) – frododot

4

一個派生類型的數組不是一個基類型的數組!雖然指向派生對象的指針轉換爲指向基礎對象的指針,但不能將基指針用作指向基礎對象數組的指針。

的理由很簡單:當你做一個操作像array[i]的編譯器編譯這*(array + i)和內部地址算術的東西做這樣array + sizeof(T) * i其中T是靜態類型的array。現在,對於從基本類型B派生的D類型,它通常認爲是sizeof(B) < sizeof(D)。因此,如果將派生對象數組視爲基礎對象數組,則索引算術將最終訪問對象中或多或少隨機位置的元素。

+0

是的,現貨。謝謝。 – frododot