获取基类指针,但调用派生类函数

Create Function taking base class pointer but calling derived class function

本文关键字:调用 派生 类函数 基类 指针 获取      更新时间:2023-10-16

我有两个类A (base)和B(衍生自A):

class A { };
class B : public A
{
    int data;
public:
    int get_data() { return data; }
};

现在我有一个函数测试,它接受基类指针并调用派生类函数:

void test(A * ptr)
{
    ptr->get_data();
}

但问题是ptr可能指向A的对象或B的对象。如果指向B的对象,则OK,但如果指向A的对象,则有问题。

此外,我不想使get_data()虚,因为data不是A的对象的属性。

如何检查ptr是否指向B的对象?我能想到的一个解决方案是dynamic_cast,并检查NULL。这是最好的解决方案还是我能有更好的解决方案?

这意味着您的test函数在说谎。它说它将接受指向任何A对象的指针,甚至是从A派生的类型,但该函数实际上不会为B以外的任何对象工作。你最好去做一个B*:

void test(B* ptr)
{
   ptr->get_data();
]

如果你可以改变AB的接口(包括添加虚函数),如果你可以重新洗牌test函数中的代码,你可以使用"访问者模式"。下面是使用BaseDerived类的示例:

class Visitor
{
public:
    void Visit(Base * B)
    {
    }
    void Visit(Derived * D)
    {
        int data = D->get_data();
    }
};
class Base
{
public:
    virtual void Accept(Visitor * V )
    {
        V->Visit(this);
    }
};
class Derived: public Base
{
public:
    int get_data()
    {
        return data;
    }
    virtual void Accept(Visitor * V )
    {
        V->Visit(this);
    }
private:
    int data;
};

通过这种方式,您可以遍历Base*的向量,调用每个元素的Accept,并且知道只有对于Derived元素才会调用get_data方法。

继承为is-a关系建模。很明显,在代码中B不是A,继承是错误的模型。你在评论中提到,你有一个矢量,它被传递给一个封闭的,更大的函数。我的建议是:

  1. std::vector<boost::any>
  2. std::vector<boost::variant<A,B>>

编辑下面是一个使用boost变量的例子:

class A
{
public:
    void DoIt()
    {
        std::cout << "did it!" << "n";
    }
};
class B
{
public:
    void GetIt()
    {
        std::cout << "got it!" << "n";
    }
};
typedef boost::variant<A,B> ab_t;
typedef std::vector<ab_t> list_ab;
void test(list_ab& list)
{
    std::for_each(std::begin(list), std::end(list), [](ab_t& item)
    {
        if(A* a = boost::get<A>(&item))
            a->DoIt();
        if(B* b = boost::get<B>(&item))
            b->GetIt();
    });
}

你说实际上你有一个元素a或B的向量,那么你的测试函数实际上看起来像:

void test( A ** ptr )

然后你可以使用c++的重载功能来创建一个实用程序函数,正确的函数将被调用:

void test( A ** ptr ) {
    A * elem;
    int i=0;
    elem = ptr[i++];
    while(elem) {
        testElement(elem);
        elem = ptr[i++];
    }
}
void testElement( A * ptr ) { }
void testElement( B * ptr ) {
    ptr->get_data();
}