【问题标题】:How to call derived class method from base class pointer?如何从基类指针调用派生类方法?
【发布时间】:2013-09-23 23:30:50
【问题描述】:

我有一个类似于下面的类结构

class A
{
public:
    A(void);
    ~A(void);

    void DoSomething(int i)
    {
        std::cout << "Hello A" << i << std::endl;
    }
};

class B : public A
{
public:
    B(void);
    ~B(void);

    void DoSomething(int i)
    {
        std::cout << "Hello B" << i << std::endl;
    }
};

class Ad : public A
{
public:
    Ad(void);
    ~Ad(void);
};

class Bd : public B
{
public: 
    Bd(void);   
    ~Bd(void);
};

我想将派生类的实例作为 A* 的集合存储在容器(标准映射)中,然后遍历容器并为每个实例调用方法。

#include "A.h"
#include "B.h"
#include "Ad.h"
#include "Bd.h"
#include <map>
int main(int argc, char** argv)
{
    std::map<int,A*> objectmap;
    objectmap[1] = new Ad();
    objectmap[2] = new Bd();

    for (std::map<int,A*>::iterator itrobject = objectmap.begin();
         itrobject!=objectmap.end(); itrobject++)
    {
        itrobject->second->DoSomething(1);
    }
    return 0;
}

以上代码产生以下输出。

Hello A1
Hello A1

我期待的地方

Hello A1
Hello B1

因为我希望 B 中的 DoSomething 隐藏 A 中的 DoSomething,并且因为我正在存储 A 指针,我希望没有对象切片(并且在调试器中查看对象指针表明该对象尚未被切片)。

我尝试过向下转换和动态转换指向 B 的指针,但它会切掉 Bd 的数据成员。

有什么方法可以调用 B::DoSomething 而无需将指针转换为 Bd?如果没有,如果我有许多 B 派生类(例如 BdaBdbBdc 等),有什么方法可以使用 RTTI 来知道将其转换为哪个派生类?

【问题讨论】:

  • 你需要使那个函数virtual
  • @PaulGriffiths 你应该让你的评论成为答案。
  • 如果我将 A::DoSomething 设为虚拟,那么我需要在 Ad 中实现 DoSomething,对吗?
  • @helloworld922:好电话,已添加。
  • 我有点不明白为什么人们会竭尽全力输入这样一个详细的问题,只是为了提交与之前迭代完全相同的标题。他们害怕搜索吗? stackoverflow.com/questions/15853031/…

标签: c++ inheritance


【解决方案1】:

您需要在两个类中创建 DoSomething() 一个 virtual 函数以获得您所追求的多态行为:

virtual void DoSomething(int i) { ...

你不需要在每个子类中都实现虚函数,如下例所示:

#include <iostream>

class A {
    public:
        virtual void print_me(void) {
            std::cout << "I'm A" << std::endl;
        }

        virtual ~A() {}
};

class B : public A {
    public:
        virtual void print_me(void) {
            std::cout << "I'm B" << std::endl;
        }
};

class C : public A {
};

int main() {

    A a;
    B b;
    C c;

    A* p = &a;
    p->print_me();

    p = &b;
    p->print_me();

    p = &c;
    p->print_me();

    return 0;
}

输出:

我是一个
我是B
我是A

【讨论】:

  • 抱歉误导评论。如果我在 A 中使 DoSomething 成为虚拟,那么我将需要在 Ad 中实现 DoSomething,以及 A 的所有其他派生类。我希望避免这种情况,因为它们中有很多。这是实现这一目标的唯一方法吗?
  • 如 cmets 中所述,您不必在每个子类中都实现虚函数。如果您没有在子类中实现它,您的子类将使用基类中的实现。
  • 适用于我的测试项目,但不适用于我的实际项目。未解析的外部符号。它一定是别的东西。这是另外一回事。感谢您的回复。
猜你喜欢
  • 2014-02-15
  • 1970-01-01
  • 1970-01-01
  • 2016-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
相关资源
最近更新 更多