Есть ли какая-либо проблема с частично переопределяющим рядом виртуальных функций, определенных базовым классом?
Мой компилятор обеспечивает соблюдающее предупреждение:
overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass".
Классы похожи на это:
class MyBaseClass
{
public:
virtual void setValue(int);
virtual void setValue(SpecialType*);
}
class MyDerivedClass : public MyBaseClass
{
public:
virtual void setValue(int);
}
Простой способ избавиться от этого предупреждения состоит в том, чтобы использовать различные названия основных функций, но я хотел знать, был ли какой-либо неопровержимый довод для фиксации этого определенного предупреждения. Я не полагаю, что это нарушает стандарт C++. Мое предположение - то, что это должно предупредить программиста, что они, возможно, забыли реализовывать поведение для всех возможных входных типов. В нашем случае это является намеренным для исключения некоторых определенных типов.
Вы препятствовали бы подавлению этого предупреждения в целом?
Переопределение для setValue(int)
скрывает setValue(SpecialType*)
базового класса (см. C++ FAQ Lite), так что при попытке вызова setValue(new SpecialType())
вы получите ошибку.
Вы можете избежать этого, добавив директиву using
к производному классу, который "импортирует" перегрузки из базового класса:
class MyDerivedClass : public MyBaseClass
{
public:
using MyBaseClass::setValue;
virtual void setValue(int);
};
Предупреждение правильное, он называется «скрытие имени». Переменная типа MyderedClass
не может вызвать setValue (SpecialType *)
.
Перегрузка и имя, скрывающиеся в C ++
в телефонном разговоре с Брэдом прошлой ночью, он рассказал мне о странной проблеме, которую он встречался в своей новой работе C ++. Конечно, это, вероятно, не имеет большого значения для людей с обширным опытом C ++, но для тех из нас, которые живут в управляемых кодевых мирах, это казалось странным.
В C ++, когда у вас есть класс с перегруженным методом (функция элементов, что, как вы хотите вызвать его), и вы затем расширяете и переопределите этот метод, вы должны переопределить все перегруженные методы.
Я понимаю тот случай, когда вы изменили метод подписи в дочернем классе, тем самым недействуя установленный интерфейс. В этом случае, хотя, кажется, контрактю, так как вы не меняете интерфейс, но выборочно переоценивают. Который отличается.
Например:
class FirstClass
{
public:
virtual void MethodA (int);
virtual void MethodA (int, int);
};
void FirstClass::MethodA (int i)
{
std::cout << "ONE!!\n";
}
void FirstClass::MethodA (int i, int j)
{
std::cout << "TWO!!\n";
}
простой класс здесь с двумя методами (или одним перегруженным методом). Вы хотите переопределить двухпараметрическую версию, поэтому вы продолжаете следующую:
class SecondClass : public FirstClass
{
public:
void MethodA (int);
};
void SecondClass::MethodA (int i)
{
std::cout << "THREE!!\n";
}
Теперь, когда вы используете экземпляр SecondClass, большинство программистов Java или C # могут предположить, что вы можете позвонить:
int main ()
{
SecondClass a;
a.MethodA (1);
a.MethodA (1, 1);
}
Однако второй звонок выиграл Работа, поскольку двухпараметрический метод не виден. Вы можете получить указатель и добраться до FirstClass, но экземпляр второгокласса не наследует непосредственным методам непосредственно.
Понятно, что компилятор хочет предупредить вас: вы создали подкласс, который ведет себя по-разному, когда дает ему INT
, но вы не изменили его поведение при предоставлении его Specialtype *
.
Хотя это может быть намерением, очень возможно, что измененное поведение также необходимо для других перегруженных виртуальных функций.
Я хотел бы, чтобы компилятор предупредил меня сложнее, время я проигнорировал! Мой переопределенный метод оказался компиляцией и хорошо работать в моем сценарии, но какой-то другой сценарий пошел действительно не так из-за перегрузки, не переоцененной.
Подумайте дважды, прежде чем отключить это предупреждение!
Если вы хотите, чтобы исходное поведение сохранилось, легко просто позвонить родительскую функцию:
class MyDerivedClass : public MyBaseClass {
virtual void setValue(int);
// explicit: keep original behavior for SpecialType
virtual void setValue( SpecialType* p ) { MyBaseClass::setValue(p); }
};