在C ++中将指向基类的指针传递给派生类的成员函数

时间:2009-12-14 22:28:57

标签: c++ inheritance interface

如何从接收指向基类的指针的实例的成员函数中访问派生类的数据?我有:

    class Base{
        public:
            virtual void compare(Base*)=0;
    };

    class A: public Base{
        int x;
        public:
            A();
            void compare(Base*);
    };

    class B: public Base{
        char c;
        public:
            void compare(Base*);
    };

    A::A(){
        x = 1;
    };

    void A::compare(Base *p){
        cout<< "A's x is " << x << "\n";
        cout<< "Argument's x is " << p->x;
    };

    void B::compare(Base* p){
        cout<< "B's compare() is running\n";
    };

    int main(const int argc, const char *argv[]){
        A a1 = A();
        A a2 = A();
        B b = B();
        a1.compare(&a2);
    }

由于Base没有数据成员x,因此无效。在我写这篇文章时,我发现通过指向Base接口类的指针来访问派生类的数据成员并不是一个好主意。

在我的问题中,我需要将不同的派生类与Base类提供的相同接口进行比较。 Base的接口必须包含compare(Base*)成员函数。实例的比较方式可能因派生类别而异。显然,比较逻辑应该在这些类的成员函数中编码。我该如何实施这个模型?

6 个答案:

答案 0 :(得分:4)

除非您的派生类共享一些您想要通过基类访问的常用数据,否则没有简单的解决方案。
例如,除非您的派生类数量非常少,否则在每个派生类中动态转换都是多余的,缓慢且容易出错的。

更大类型层次结构的一个解决方案是double dispatch

答案 1 :(得分:1)

您可以使用dynamic_cast将基指针强制转换为其中一种派生类型。请务必正确处理dynamic_cast无法转换指针的情况。

我应该补充一点,这是一种有臭味的方法。如果对象真的具有可比性,那么它们在基类级别上应具有可比性。

答案 2 :(得分:1)

你可能会跛着回家,这取决于你的对象层次结构:

bool A::compare(Base *p){
    A *pa = dynamic_cast<A*>(p);
    if (!pa) return false;
    return x == pa->x;
};

实际上,实施多态比较存在严重困难。问题是如果a是A的实例,而c是A的某个派生类C的实例,那么使用这种技术你很容易就会得到a.compare(c)为true,但是c.compare (a)是假的。

你可能会更好:

  • 使你的比较非多态,并把它放在调用者上,只有当他们关心的是他们是相同的时候才将它们作为类型Base进行比较,直到Base可以告诉他们。但是对于调用者来说这不太有用,而对于没有数据成员的Base来说完全没有意义。
  • 在Base中进行非虚拟比较,检查两个对象是否相等typeid,如果不相等则返回false,如果是,则调用其中两个对象的虚拟comparisonImpl函数。然后A :: comparisonImpl知道它的参数是A的一个实例,并且可以static_cast it:

class Base {
public:
    bool compare(Base *p) {
        if (typeid(*this) != typeid(*p)) return false;
        return compareImpl(p);
    }
private:
    virtual bool compareImpl(Base *p) = 0;
};

class A : public Base {
    int x;
private:
    bool compareImpl(Base *p) {
        return x == static_cast<A*>(p)->x;
    }
};

答案 3 :(得分:1)

的dynamic_cast。

struct Base
{
    virtual bool compare(const Base*) = 0;
};

struct A : Base
{
    A()
    {
        x = 1;
    }
    virtual bool compare(const Base* other)
    {
        const A* rhs(dynamic_cast<const A*>(other));
        if(other == NULL) { return false; }
        return x == rhs->x;
    }
private:
    int x;
};

struct B : Base
{
    virtual bool compare(const Base* other)
    {
        const B* rhs(dynamic_cast<const B*>(other));
        if(other == NULL) { return false; }
        return c == rhs->c;
    }
private:
    char c;
};

答案 4 :(得分:1)

我不得不在前一段时间里一直在努力。在我的情况下,具体要求要求两个元素只有当它们实际上具有相同的确切类型时才会相等。也就是说,在比较苹果和苹果时,你只想要一个积极的匹配,但是在最大的衍生水平(金苹果到金苹果,而不是皇家嘎拉苹果。)

class base {
public:
   virtual bool compare( base const & rhs ) = 0;
};
class derived : public base {
public:
   virtual bool compare( base const & rhs ) {
      if ( typeid(*this) != typeid(rhs) ) return false;
      return *this == static_cast<derived const &>(rhs);
   }
};
bool operator==( derived const & lhs, derived const & rhs );

请注意,我们最终使用typeid + static_cast代替更常见的动态强制转换习惯用法,以强制两种类型完全相同。如果我们使用dynamic_cast那么对称可能会破坏并且:

class rederived : public derived {
public:
   virtual bool compare( base const & rhs ) {
      rederived const * p = dynamic_cast<rederived const *>(&rhs);
      return p && *this == *p;
   }
};
void test() {
   derived d;
   rederived rd;
   d.compare( rd ); // compare if derived subobject is equal, possibly true
   rd.compare( d ); // always false, d cannot be dyncamically casted to rederived
}

这又是因为我们的特定约束要求两个对象具有完全相同的类型。如果您只想检查它们是否在层次结构的一个级别中是“兼容的”(这本身就是一个非对称操作,因为左侧确定了您希望在哪个层次上执行比较)。

答案 5 :(得分:0)

这个怎么样?

int main(const int argc, const char *argv[]){
    Base a1 = new A();
    Base a2 = new A();
    Base b = new B();
    a1.compare(&a2); }