Ваше использование virtual
наследования здесь спурсистское и представляет собой красную сельдь.virtual
наследование используется для выведения из общих базовых классов только один раз; не для ввода только одной декларации для соответствующих подписей членов.
Итак, ваш конкретный класс FastCar
на самом деле имеет 3 члена, а не 2:
virtual void ICar::drive()
virtual void IFastCar::drive()
virtual void IFastCar::driveFast()
два разных drive()
кажутся взаимосвязанными, поэтому ваш дизайн кажется ошибочным.Вам не нужно наследование virtual
- вы, вероятно, хотите, чтобы IFastCar
происходило от ICar
.
class ICar {
public:
virtual void drive() = 0;
};
class IFastCar : public ICar {
public:
virtual void driveFast() = 0;
};
class Car : public virtual ICar {
public:
void drive() {};
};
class FastCar : public IFastCar {
public:
void drive() {};
void driveFast() {};
};
int main()
{
FastCar fc;
fc.drive();
fc.driveFast();
return 0;
}
Если вы тогда хотели, чтобы Car
реализовал некоторые базовые функции, которые FastCar
нанять, тогда вы можете получить FastCar
из Car
, а , что - вот почему вы хотите virtual
наследование.Просто не забудьте применить virtual
наследование в точке чуть ниже вершины ромба:
class ICar {
public:
virtual void drive() = 0;
};
class IFastCar : virtual public ICar {
public:
virtual void driveFast() = 0;
};
class Car : public virtual ICar {
public:
void drive() {};
};
class FastCar : public IFastCar, public Car {
public:
void driveFast() {};
};
int main()
{
FastCar fc;
fc.drive();
fc.driveFast();
ICar* fc_a = new FastCar;
fc_a->drive(); // invokes Car::drive() via domination
return 0;
}
Если вы скомпилируете и запустите приведенный выше код, вы получите желаемое поведение, но за счет компиляторапредупреждение.На MSVC10 это выглядит так:
1>main.cpp(19): warning C4250: 'FastCar' : inherits 'Car::Car::drive' via dominance
1> main.cpp(13) : see declaration of 'Car::drive'
Это предупреждение о том, что ваша архитектура наследования реализации может быть испорчена.И на самом деле в большинстве случаев это, вероятно, так (хотя в этом случае нет).Это может очень быстро сбить с толку, особенно программисту, который уже несколько лет пытается выяснить ваш код.Чтобы устранить эту путаницу и избежать всех предупреждений компилятора, я предпочитаю (как правило) делегирование дочернему классу, а не наследованию реализации.
class ICar {
public:
virtual void drive() = 0;
};
class IFastCar : virtual public ICar {
public:
virtual void driveFast() = 0;
};
class ICarImpl
{
public:
void drive_impl() {};
};
class IFastCarImpl
{
public :
void driveFast_impl() {};
};
class Car : public virtual ICar, protected ICarImpl {
public:
void drive() { drive_impl(); }
};
class FastCar : public IFastCar, protected ICarImpl, protected IFastCarImpl {
public:
void driveFast() { driveFast_impl(); }
void drive() { drive_impl(); }
};
int main()
{
FastCar fc;
fc.drive();
fc.driveFast();
ICar* fc_a = new FastCar;
fc_a->drive();
return 0;
}
Это выполняет обычную задачунаследования реализации - хранение только одного общего набора кода, который может совместно использоваться несколькими конкретными классами, что упрощает обслуживание.