Ошибка компилятора при переопределении виртуальных методов

Использование компилятора 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:: перед именами моих методов и почему я вижу эти разнообразные ошибки компилятора? Любое объяснение приветствуется!


person Stefan Hubert    schedule 07.04.2010    source источник
comment
Почему вы в первую очередь помещаете все эти A :: в свой код? Чего вы пытаетесь достичь? Не думаю, что я когда-либо использовал этот синтаксис в этом контексте (что кажется очень простым наследованием).   -  person Daniel Daranas    schedule 07.04.2010
comment
@ Дэниел: Признаюсь, я действительно не знаю, что делал. У меня была надежда, что если кто-то изменит имена виртуальных методов в A, я увижу ошибки компилятора в определениях перезаписи B. Если опустить A ::, компилятор не знает, пытаюсь ли я перезаписать методы A или ввести свои собственные, и компилятор не будет генерировать ошибки, если такие определения методов не существуют в A. Имеет ли это смысл?   -  person Stefan Hubert    schedule 07.04.2010
comment
Если вам нужна такая возможность, используйте C вместо C ++. :П   -  person Judge Maygarden    schedule 07.04.2010
comment
@Stefan: Вы хотите сказать, что хотите гарантировать, что A реализует некоторые функции в B? Если вы удалите ключевое слово virtual, вы не переопределите базовый класс.   -  person Jon Cage    schedule 07.04.2010
comment
@Stefan: Тогда этот вопрос может вас заинтересовать: stackoverflow.com/questions/497630/   -  person ZoogieZork    schedule 07.04.2010
comment
@John: Аэмм ... нет, я не это хотел сказать, скорее .... @ZoogieZork: спасибо, да, этот вопрос касается того, что я изначально задумал с моим A:: материалом в B.   -  person Stefan Hubert    schedule 07.04.2010


Ответы (5)


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
}

Надеюсь это поможет.

person Matthieu M.    schedule 07.04.2010
comment
Потому что синтаксис такой. Вам не нужно указывать дважды имя базового класса. Вы уже сделали это class B: public A. A :: myMethod () используется только тогда, когда вы вызываете myMethod, и он также должен быть статическим. - person Draco Ater; 07.04.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;

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

person wheaties    schedule 07.04.2010

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

person Judge Maygarden    schedule 07.04.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

person Timmmm    schedule 07.04.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 решит ваши проблемы с компиляцией.

person Jon Cage    schedule 07.04.2010