关于c ++:覆盖虚拟方法时的编译器错误

Compiler error when overriding virtual methods

使用VC71编译器并获取编译器错误,我不理解。举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A
{
public:
  virtual int& myMethod() = 0;
  virtual const int& myMethod()const = 0;
};

class B: public A
{
public:
  // generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
  virtual int&  A::myMethod();

  // error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'
  virtual const int& A::myMethod() const;
};

当我切换b中两个方法定义的顺序时,我会看到一个不同的编译器错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
class B: public A
{
public:
  // error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
  virtual const int& A::myMethod() const;

  // error C2556: 'int &B::myMethod(void)' : overloaded function differs only by return type from 'const int &B::myMethod(void)'
  // error C2373: 'B::myMethod' : redefinition; different type modifiers
  virtual int&  A::myMethod();

  // error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'

};

但是,如果我省略了A::的内容,那么就不会得到任何编译器错误:

1
2
3
4
5
6
class B: public A
{
public:
  virtual int&  myMethod();
  virtual const int& myMethod() const;
};

那么,在我的方法名前面的A::究竟是什么?为什么我会看到这些不同的编译器错误?欢迎解释!


1
2
3
4
5
6
class B: public A
{
public:
  virtual const int& myMethod() const;
  virtual int& myMethod();
};

去掉b定义中的A::,效果很好。

编辑:错过了问题中的某些内容…

::用于表示范围。您可以将它与名称空间或类一起使用,以明确限定以后在何处查找符号。

与方法一起使用,这意味着您希望精确地调用哪个方法,例如:

1
2
3
4
5
6
struct A { int getInt(); }

struct B: public A { int getInt(); }

B b;
b.A::getInt(); // calls A::getInt, not B::getInt

对于方法声明来说,这完全是不正常的,方法是在一个范围内声明的,并且自然属于这个范围:

1
2
3
4
5
6
7
8
9
namespace foo
{
  int bar();     // full name is foo::bar
}

struct Foo
{
  static int bar();     // full name is Foo::bar
};

但是,当提到模式时,它是有用的:

1
2
3
4
using foo::bar;

int a = bar();    // calls foo::bar because we asked the compiler
                  // to import it in the current scope

或者正如我们已经看到的,直接调用方法:

1
2
3
4
5
6
int B::getInt()                 // definition outside the class
                                // we need to specify what we define
{
  return this->A::getInt() + 1; // call A::getInt, without precising it
                                // we would have a stack overflow
}

希望这有帮助。


我假设您这样做是为了处理多重继承,即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A
{
public:
  virtual int& myMethod() = 0;
};

class A2
{
public:
  virtual int& myMethod() = 0;
};

class B: public A, public A2
{
public:
  virtual int&  A::myMethod();
  virtual int&  A2::myMethod();
};

但不是这样的。B只能有一个myMethod()。请参见这里:

http://www.cprogramming.com/tutorial/multiple_inheritance.html


您不应该将函数声明范围放在类声明内。在C++标准中没有指定错误消息。因此,每个编译器显然会为这种奇怪的东西生成不同的消息。


A::表示您正在从A调用函数。下面是一个示例,说明您为什么要使用::

1
2
3
4
5
6
7
8
9
10
11
class A{
public:
   int m_val;
};

class B{
public:
   int m_val;
};

class C: public A, public B{}

现在,当我想在C中为m值设置一个值时,我必须这样做:

1
2
C myC;
myC::A::m_val = 4;

这样编译器就不会混淆您访问的变量。


在我看来,您好像尝试将.cpp文件内容移动到.h文件中?这些作用域声明在.cpp定义文件中是有意义的,但不应该出现在.h声明中(正如其他人已经指出的那样)。

1
2
// generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual int&  A::myMethod();

所以这里你是说你使用的是一个虚拟函数,它实现了一个在别处定义的接口函数。把A::放在前面,你的意思是你的函数正在覆盖在A中定义的mymethod。如果您有两个基本类(BC作为参数,它们都具有相同名称的函数,那么您可以使用virtual B::ThatFunction()来重写b的imlpement,或者使用virtual C::ThatFunction()来重写c的实现。

删除A类中的所有A::将修复编译问题。