Ошибка компилятора при переопределении виртуальных методов - PullRequest
3 голосов
/ 07 апреля 2010

Использование компилятора VC71 и получение ошибок компилятора, которые я не понимаю. Вот пример

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, тогда я вижу другую ошибку компилятора:

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::, я не получу ошибку компилятора:

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

Итак, что именно делает A:: перед именами моих методов и почему я вижу эти разные ошибки компилятора? Любое объяснение приветствуется!

Ответы [ 5 ]

2 голосов
/ 07 апреля 2010
class B: public A
{
public:
  virtual const int& myMethod() const;
  virtual int& myMethod();
};

Удалите A:: в определении B, и оно хорошо работает:)

РЕДАКТИРОВАТЬ: пропустил что-то в вопросе ...

:: используется для обозначения области. Вы используете его либо с пространствами имен, либо с классами, чтобы явно указать, где искать символ впоследствии.

Используется вместе с методами, это означает, что вы хотите точно определить, какие вызовы методов, например:

struct A { int getInt(); }

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

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

Это совершенно не в порядке для объявления метода, метод объявляется в области видимости и, естественно, принадлежит этой области:

namespace foo
{
  int bar();     // full name is foo::bar
}

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

Однако это полезно при обращении к режиму:

using foo::bar;

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

Или, как мы уже видели, для прямого вызова метода:

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 голос
/ 07 апреля 2010

Я предполагаю, что вы делаете что-то подобное для обработки множественного наследования, то есть:

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

1 голос
/ 07 апреля 2010

Вы не должны охватывать объявления функций внутри объявления класса.Сообщения об ошибках не указаны в стандарте C ++.Таким образом, каждый компилятор, очевидно, будет выдавать разные сообщения для чего-то такого странного.

1 голос
/ 07 апреля 2010

A :: означает, что вы вызываете функцию из A. Вот пример того, почему вы хотите использовать A ::

class A{
public:
   int m_val;
};

class B{
public:
   int m_val;
};

class C: public A, public B{}

Теперь, когда я хочу установить значение для m_val в C, мне нужно будет сделать:

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

чтобы компилятор не путался между тем, к какой переменной вы обращаетесь.

0 голосов
/ 07 апреля 2010

Мне кажется, что вы пытались переместить содержимое файла .cpp в файл .h?Эти объявления области видимости имеют смысл в файле определения .cpp, но их не должно быть в объявлении .h (как другие уже указали).

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

Итак, вы говорите:использовать виртуальную функцию, которая реализует интерфейсную функцию, которая определена в другом месте.Помещая A:: перед ним, вы говорите, что ваша функция переопределяет myMethod, который определен в A.Если у вас есть два базовых класса (B и C для аргументов), которые имеют функцию с одинаковым именем, вы можете использовать virtual B::ThatFunction() для переопределения имплементации B или virtual C::ThatFunction() для переопределения реализации C.

Удаление всех A:: в классе A решит ваши проблемы с компиляцией.

...