关于指针:在向量C ++中从超类调用子类方法

Calling subclass methods from superclass in a vector C++

我试图在一个向量中添加一些子类元素,遍历它们调用一个被重写的方法,并希望它在可能的情况下调用被重写的方法。然而,我发现它似乎只是在调用超类方法。

我学习了Java,我不确定为什么它在C++中这样做。我尝试使用超类指针的向量重写代码,并将子类的指针强制转换为超类。然后通过指针访问这个。

理想情况下,我不想在向量中放置指针列表,因为我必须手动删除每个指针(我相信?)为了防止内存泄漏,因为我将使用new创建对象,以便它们在方法调用之后保持不变,以便将它们添加到向量中。

有没有更好的方法可以做到这一点,或者当父类不需要时,我坚持使用指针并对创建的对象调用delete?向量最好是类X的列表,而不是类X的指针列表。

我的结构是:

1
2
3
4
5
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() }

代码来演示我理想中想要做的事情,但只通过调用超类方法来显示它的中断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>

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

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

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
    }

}


要获得所需的多态行为,需要向要在派生类中重写的基类中的函数添加virtual说明符。

1
2
3
4
5
class A {
public:
    virtual void talk() { printf("A
"
); }
};

您还应该习惯于在派生类中的重写函数上添加override说明符,以便编译器可以帮助您解决这些问题。

1
2
3
4
5
6
7
class B: public A {
public:
    virtual void talk() override { printf("B
"
); }
//                      ^ Compiler will report an error if base class' function
//                        is not virtual.
};

此外,不能将派生对象分配给基类的实例,否则将发生切片。

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

使用virtual说明符的实况示例

没有virtual说明符的实况示例


如果不使用指针,则在将对象复制到向量中时,将得到"对象切片"。这会将对象减少到vector模板参数中声明的基类型。所以没有子类,所以没有子类方法可以调用,即使该方法是虚拟的。


我认为您缺少的是方法声明中的virtual关键字。如果要在父类中调用方法时获取子类方法,则必须声明这些方法virtual


方法应该是虚拟的。在Java中,默认方法是虚拟的。

1
2
3
4
5
6
7
8
9
10
11
class A {
  public:
    virtual void talk() { printf("A
"
); }
};

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


您应该将这些方法声明为virtual,以便能够在子类中重写它们。另外,最好将析构函数设为虚拟的。

1
2
3
4
5
6
7
8
9
10
11
12
13
class A {
public:
   virtual void talk() { printf("A
"
); }
   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
"
); }
};