派生类的虚函数在从base调用时会导致“not member”错误

时间:2013-03-30 12:11:47

标签: c++ compiler-errors virtual

#include<iostream>

class A {
private :
    int _a;

public :
    A(int i=0) : _a(i){}
    virtual void setA(int i) { _a = i;}
    virtual int getA(){ return _a;}
};

class B : public A
{
private :
    int _b;

public :

    B(int i) : _b(i){}
    virtual void setB(int i) { _b = i;}
    virtual int getB(){ return _b;}
};

int main(){
A* a1 = new B(10);
std::cout << a1->getA() << "\t " << a1->getB() << std::endl;
return 0;
}

编译时我收到以下错误:

test.cpp(28): error C2039: 'getB' : is not a member of 'A'

不应该a1获得getB,因为它实际上是指向B的指针吗?

4 个答案:

答案 0 :(得分:3)

编译器会告诉您确切的原因:

'getB' : is not a member of 'A'

编译器根据指针的类型进行编译时检查,因为它无法在A中找到它所报告的方法。请注意,在编译时,编译器可能知道也可能不知道指针a1指向哪个对象,它可能是AB或公共派生自A的任何类。编译器只检查指针的类型,并检查被访问的成员是否属于该类 对于您,a1指向B的对象,因此可以像B那样对待,但编译器a1A类型的指针,在编译时,它只将其视为A


虽然上面已经详细说明了“为什么这不起作用”的答案,但我认为我应该在“你如何解决这个问题”。

简单的答案是为getB()实施A。这通常是正确的做法 - 如果它以某种方式“禁止”在没有此属性的对象上调用getB,那么就做一些事情 - 打印错误,退出程序,或者其他什么是当有人在代码中出错时(最好在某个地方打印一条消息,然后停止,以便明确出错的地方并且可以调试),这是“正确的”。

替代方案,例如使用动态强制转换,也可以使用。但您仍然必须知道对象是否是B类 - 或者检查指针是否返回NULL。

虚函数的关键在于,您可以使用派生类中的新变量覆盖基类中的函数。它不支持在派生类中添加NEW函数。支持“新功能”的方法是添加参数:

class A
{
 public: 
    ...
    virtual int get(char v)
    {
       if (v == 'A') return _a;
       else
       {
          std::cerr << "Error: Requesting invalid variable: '" << v << "'" << std::endl;
          return -1;
      }
    }
    ...
}


class B: public A
{
   ...
   virtual get(char v)
   {
      if (v == 'B')
         return b;
      return A::get(v);
   }

   ...
}

现在只需稍作修改即可:

std::cout << a1->get('A') << "\t " << a1->get('B') << std::endl;

答案 1 :(得分:1)

您必须在A类中拥有成员函数:

virtual int getB()
{
 // do something or not
}

之后,当你致电a1->getB()时,它将调用B类的成员函数。

另一种方法是在a1上使用dynamic_cast

A* a1 = new B(10);
B* b1=dynamic_cast<B*>(a1);
std::cout << b1->getA() << "\t " << b1->getB() << std::endl;

答案 2 :(得分:1)

编译器不知道a的动态类型信息。您可以使用dynamic_cast

将其强制转换为动态类型
dynamic_cast<B*>(a1)->getB();

Live Demo

答案 3 :(得分:0)

虽然a1是指向B类对象的指针,但编译器在运行时才知道a1指向B对象。因此,在编译时,由于A类中没有getB方法,因此会遇到错误。