2014-07-19 53 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

相关问题