2014-07-19 55 views
5

我想將一些子類描述的元素添加到一個向量中,遍歷它們調用一個重寫的方法,並希望它在可能的情況下調用重寫的方法。但是我發現它似乎只是調用超類方法。從超類的向量中調用子類方法C++

我學習了Java並且不確定它爲什麼在C++中這樣做。我嘗試使用超類的指針向量重寫代碼,並將子類的指針投射到超類。通過指針訪問這個工作。

理想情況下,我不想要將指針列表放入向量中,因爲此後我必須手動刪除每個(我相信?)以阻止內存泄漏,因爲我將用new創建對象,以便它們保持過去該方法調用將它們添加到向量中。

有沒有更好的方法來做到這一點,或者我堅持使用指針,並調用刪除創建的對象時父類不需要?最好的載體是類X的一個列表,而不是X類的指針列表

我的結構是:

class a { vector vec of class X, 
    method to create and add an instance of X into vector vec, 
    method to create and add an instance of Y into vector vec } 
class X { talk() } 
class Y : public X { talk() } 

代碼來說明什麼,我非常想做的事,但顯示出其只破父類方法:

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <vector> 

class A { 
    public: 
    virtual void talk() { printf("A\n"); } 
}; 

class B: public A { 
    public: 
     void talk() { printf("B\n"); } 
}; 

int main(void) { 
    std::vector<A> vec; 
    std::vector<A*> vec2; 
    A a; 
    B b; 
    a.talk(); 
    b.talk(); 

    vec.push_back(a); 
    vec.push_back(b); 
    vec2.push_back(&a); 
    vec2.push_back(&b); 

    for(int i = 0; i < vec.size(); i++) { 
     vec[i].talk(); 
     vec2[i]->talk(); //bad but short for example 
    } 

} 
+2

你確實需要指針(可能是智能指針,比如'std :: unique_ptr')才能獲得多態行爲。參見[「對象切片」](http://en.wikipedia.org/wiki/Object_slicing)。它在Java中工作,因爲'MyClass obj'有效地聲明瞭一個指向'MyClass'的指針。 –

+1

'talk()'在'A'中不是虛擬的,所以沒有方法可以覆蓋。編譯器將使用什麼是靜態類型,即「A」。 – 0x499602D2

+0

@ 0x499602D2此代碼的第一個版本中的錯誤,已修復,已添加虛擬,仍未按預期工作。 – Chewett

回答

3

要獲得您想要的多態行爲,您需要將virtual說明符添加到要在派生類中重寫的基類中的函數。

class A { 
public: 
    virtual void talk() { printf("A\n"); } 
}; 

您還應該增加對重載函數的override符在派生類中,這樣編譯器可以幫助您與這些類型的問題的習慣。

class B: public A { 
public: 
    virtual void talk() override { printf("B\n"); } 
//     ^Compiler will report an error if base class' function 
//      is not virtual. 
}; 

您也可以不是派生對象分配給一個基類,或slicing will occur的一個實例。

std::vector<A> vec; 
/* ... */ 
B b; 
/* ... */ 
vec.push_back(b); // Slicing. Information only in B is lost. 

Live example using virtual specifier

Live example without virtual specifier

+0

這樣做不起作用FYI,因爲我仍然從輸出中獲得AB AA AB。 – Chewett

+0

最初的代碼被錯誤地鍵入,修復它在我的IDE,但不在這裏,現在修復。 – Chewett

+0

可能想刪除您的答案的第一部分,因爲它不是一個問題(只是複製代碼是大聲笑)。 否則看起來不錯,謝謝:) – Chewett

0

如果要在申報方法爲virtual要能覆蓋它們的子類。此外,讓析構函數變爲虛擬是一個好習慣。

class A { 
public: 
    virtual void talk() { printf("A\n"); } 
    virtual ~A(){} 
}; 

class B: public A { 
public: 
    // using virtual is not really necessary here, but it's good for clarity. 
    virtual void talk() { printf("B\n"); } 
}; 
+0

這是上傳代碼時出現的一個錯誤,我在上傳之前修正了這個錯誤,但仍然有輸出AB AA AB – Chewett

0

該方法應該是virtual
在java方法默認是虛擬的。

class A { 
    public: 
    virtual void talk() { printf("A\n"); } 
}; 

class B: public A { 
    public: 
     virtual void talk() override { printf("B\n"); } //override key word is in C++ 0x and above 
}; 
+0

這是上傳代碼時出現的錯誤,我在上傳之前修正了該錯誤,並且仍然有輸出AB AA AB – Chewett

0

我想你缺少的是方法聲明中的virtual關鍵字。如果要在調用父類中的方法時訪問子類方法,則必須將方法聲明爲virtual

+0

這是一個在上傳代碼時出現錯誤,我在上傳之前修正了這個錯誤,並且仍然有輸出AB AA AB – Chewett

0

如果不使用指針,當你複製對象到載體中,你會得到「對象切片」。這將對象減少爲在矢量模板參數中聲明的基本類型。所以沒有子類,所以即使方法是虛擬的,也不需要調用子類方法。

+0

@downvoter哦真的嗎? – EJP

相關問題