Безопасное удаление C ++ скрытого виртуального предупреждения

Я получаю предупреждение компиляции от компилятора Sun C ++ 5.10 о скрытом виртуальном методе в некотором существующем коде, который я изменяю. По какой-то причине автор не реализовал переопределение функции для данного типа данных. Я воссоздал ситуацию здесь:

// First the data types
struct Shape {};
struct Square : public Shape {};
struct Circle : public Shape {};
struct Triangle : public Shape {};

// Now the visitor classes
struct Virtual
{
virtual ~Virtual() {}

virtual void visit( Square& obj ) {}
virtual void visit( Circle& obj ) {}
virtual void visit( Triangle& obj ) {}
};

struct Concrete : public Virtual
{
void visit( Square& obj ) {}
void visit( Circle& obj ) {}
};

int main()
{
Concrete myConcrete;

return 0;
}

Concrete класс не реализует void visit( Triangle& obj ) {} и это вызывает следующее сообщение об ошибке:

"pv_block.cpp", line 20: Warning: Concrete::visit hides the virtual function
Virtual::visit(Triangle&).

Код работает нормально, но было бы неплохо удалить это предупреждение. Поэтому я хотел бы реализовать эту функцию так, чтобы компилятор был удовлетворен, но таким образом, чтобы ее нельзя было использовать — желательно обнаруживать во время компиляции — поскольку в настоящее время она явно не нужна.

Есть ли способ реализовать утверждение компиляции, чтобы разрешить компиляцию, но предотвратить использование? У меня нет доступа ни к Boost, ни к C ++ 11.

3

Решение

Почему вы хотите предотвратить использование? Даже если вы (каким-то образом) делаете это так, чтобы следующее (A) не скомпилировалось:

Triangle t;
Concrete x;
x.visit(t);

следующее (B) все еще будет работать:

Triangle t;
Concrete x;
static_cast<Virtual&>(x).visit(t);

Так что ИМО, не имеет смысла пытаться предотвратить его вызов. Я бы решил предупреждение, добавив используя декларацию в Concrete класс, как это:

struct Concrete : public Virtual
{
using Virtual::visit;
void visit( Square& obj ) {}
void visit( Circle& obj ) {}
};

Это отключит предупреждение и включит (A). Но я не верю, что в этом случае включить (A) неправильно.

5

Другие решения

Хотя я не обязательно согласен с вашим дизайном; Я думаю, что предупреждение действительно и должно быть рассмотрено как пример для пересмотра. Однако, если это то, что вы хотите сделать, вы можете просто добавить туда декларацию и изменить доступ к защищенному или что-то в этом роде.

struct X {
virtual void f() {}
virtual void f(int) {}
};

struct Y : public X {
virtual void f() {}
virtual void f(int);
};

int
main() {
Y y;
y.f(10);
}

undefined reference to `Y::f(int)'
1

Единственное реальное решение — отключить предупреждение компилятора.
Предположительно базовый класс обеспечивает реализацию по умолчанию, и
конкретный класс доволен этим. В противном случае вы можете предоставить
реализация, которая перенаправляет к реализации по умолчанию
в базовом классе:

void Concrete::visit( Triangle& obj ) { Virtual::visit( obj ); }

Лично я считаю, что это лишнее словоблудие, и я бы предпочел
избегай это.

1

Поэтому я хотел бы реализовать эту функцию так, чтобы компилятор был удовлетворен, но таким образом, чтобы ее нельзя было использовать — желательно обнаруживать во время компиляции — поскольку в настоящее время она явно не нужна.

Один из способов сделать это — объявить Concrete::visit(Triangle&) как личное:

struct Concrete : public Virtual
{
void visit( Square& obj ) {}
void visit( Circle& obj ) {}
private:
void visit (Triangle& obj);
};

Обратите внимание на отсутствие реализации. Это исключает предупреждение компилятора, но делает это за счет изменения ошибки времени компиляции, которая в настоящее время возникает из-за myConcrete.visit(myTriangle) в ошибку времени соединения.

Даже с этой декларацией все еще возможно иметь Concrete объект visit Triangle объект путем наложения Concrete Объект родительского класса: static_cast<Virtual&>(myConcrete).visit (myTriangle), Это проблема, и очень большая. Код в его нынешнем виде нарушает принцип подстановки Лискова.

Вероятно, лучше использовать using решение, предложенное Angew. Теперь дизайн класса приближается к подчинению Лискову. Обратите внимание, что по-прежнему существует проблема в отношении замены Лискова в отношении static_cast<Virtual&>(myConcrete).visit (mySquare) (а также myCircle).

1
По вопросам рекламы [email protected]