Я получаю предупреждение компиляции от компилятора 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.
Почему вы хотите предотвратить использование? Даже если вы (каким-то образом) делаете это так, чтобы следующее (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) неправильно.
Хотя я не обязательно согласен с вашим дизайном; Я думаю, что предупреждение действительно и должно быть рассмотрено как пример для пересмотра. Однако, если это то, что вы хотите сделать, вы можете просто добавить туда декларацию и изменить доступ к защищенному или что-то в этом роде.
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)'
Единственное реальное решение — отключить предупреждение компилятора.
Предположительно базовый класс обеспечивает реализацию по умолчанию, и
конкретный класс доволен этим. В противном случае вы можете предоставить
реализация, которая перенаправляет к реализации по умолчанию
в базовом классе:
void Concrete::visit( Triangle& obj ) { Virtual::visit( obj ); }
Лично я считаю, что это лишнее словоблудие, и я бы предпочел
избегай это.
Поэтому я хотел бы реализовать эту функцию так, чтобы компилятор был удовлетворен, но таким образом, чтобы ее нельзя было использовать — желательно обнаруживать во время компиляции — поскольку в настоящее время она явно не нужна.
Один из способов сделать это — объявить 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
).