我有以下两个接口,它们不是继承层次结构的一部分。然后我有两个具体的类,一个来自另一个。
class ICar {
public:
virtual void drive() = 0;
};
class IFastCar {
public:
virtual void drive() = 0;
virtual void driveFast() = 0;
};
class Car : public virtual ICar {
public:
void drive() {};
};
class FastCar : public Car, public virtual IFastCar {
public:
void driveFast() {};
};
int main()
{
FastCar fc;
fc.drive();
fc.driveFast();
return 0;
}
编译时出现以下错误:
error: cannot declare variable `fc' to be of type `FastCar'
error: because the following virtual functions are abstract:
error: virtual void IFastCar::drive()
如果我在FastCar中编写一个函数来将drive()委托给基类
,我的程序将会起作用void drive() { Car::drive(); }
可以在没有编写方法委托给基类的情况下编译FastCar吗?
注意:ICar和IFastCar由两个不同的团队创建,分为两个不同的项目。团队已就共享的操作的共同方法签名达成一致。我在实现类中使用了继承来尝试重用相同的实现部分。
答案 0 :(得分:5)
问题在于这里发生了多重继承......即使FastCar
来自Car
,基础中的drive()
版本也是如此-class Car
仅覆盖ICar::drive()
,而不是IFastCar::drive()
。因此,由于您从FastCar
派生IFastCar
,因此您需要在FastCar
中定义一个函数,该函数也会覆盖纯虚拟抽象方法IFastCar::drive()
。 ..继承的Car::drive()
不会自动覆盖IFastCare::drive()
,因为它不会从该类继承。 IFastCar::drive()
和ICar::drive()
是两个不同的纯抽象虚函数,需要单独重写。如果您想让IFastCar::drive()
的界面调用您继承的Car::drive()
函数,那么您将需要委托该继承的函数,因为您已经在FastCar::drive()
的{{1}}版本中完成了称其基类为'版本drive()
。
答案 1 :(得分:3)
问题在于Car
未实现IFastCar::drive
,而只实现ICar::drive
。第一个设计问题是为什么IFastCar
不扩展ICar
接口并重新定义相同的操作?
如果由于某种原因不是一个选项,那么你可以做的最简单的事情就是在IFastCar::drive()
中通过将请求转发到FastCar
方法来实现Car::drive
:
void FastCar::drive() {
Car::drive();
}
答案 2 :(得分:2)
你在这里使用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;
}
这实现了实现继承的通常目标 - 只保留一组可在多个具体类之间共享的通用代码,使维护更容易。
答案 3 :(得分:0)
由于ICar和IFastCar总是汽车,你可以拥有从ICar派生的IFastCar,然后像你一样实现Car和FastCar。
class ICar {
public:
virtual void drive() = 0;
};
class IFastCar : ICar
{
public:
virtual void drive() = 0;
virtual void driveFast() = 0;
};
class Car : ICar {
public:
void drive()
{
cout << "driving a normal car" << endl;
}
};
class FastCar : IFastCar
{
public:
void drive()
{
cout << "driving a fast car the normal way" << endl;
}
void driveFast()
{
cout << "driving a fast car at top speed" << endl;
}
};
int main()
{
FastCar fc;
fc.drive();
fc.driveFast();
return 0;
}