3

我有以下两个接口,它们不是继承层次结构的一部分。然后我有两个具体的类,一个派生自另一个。

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 由两个不同的团队创建,位于两个不同的项目中。团队已就共享操作的通用方法签名达成一致。我在实现类中使用了继承来尝试重用实现中相同的部分。

4

4 回答 4

5

问题在于这里发生了多重继承......即使FastCar派生自,基类中Car的版本也只覆盖,而不是。因此,由于您是从 派生的,因此您需要在某些时候定义一个函数,该函数还覆盖纯虚拟抽象方法......继承的不会自动覆盖,因为它不是从该类继承的。 和是两个不同的纯抽象虚函数,需要分别重写。如果你想让接口调用你继承的drive()CarICar::drive()IFastCar::drive()FastCarIFastCarFastCarIFastCar::drive()Car::drive()IFastCare::drive()IFastCar::drive()ICar::drive()IFastCar::drive()Car::drive()函数,那么您将需要像在FastCar::drive()专门调用其基类版本的drive().

于 2011-10-12T15:52:15.857 回答
3

问题是Car没有实现IFastCar::drive,而只有ICar::drive. 第一个设计问题是为什么不IFastCar扩展ICar接口和重新定义相同的操作?

如果由于某种原因这不是一个选项,那么您可以做的最简单的事情实际上IFastCar::drive()FastCar通过将请求转发给Car::drive方法来实现:

void FastCar::drive() {
   Car::drive();
}
于 2011-10-12T15:59:11.320 回答
2

virtual在这里使用继承是虚假的,并且是转移注意力。 virtual继承仅用于从公共基类派生一次;不要只为匹配的成员签名引入一份声明。

因此,您的FastCar具体类实际上有 3 个成员,而不是 2 个:

virtual void ICar::drive()
virtual void IFastCar::drive()
virtual void IFastCar::driveFast()

这两个不同drive()似乎是相关的,所以你的设计似乎有缺陷。您不想要virtual继承——您可能想要IFastCarICar.

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将使用的基本功能,那么您可以从 派生FastCarCar就是您想要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;
}

这实现了实现继承的通常目标——只保留一组可以在多个具体类之间共享的通用代码,从而使维护更容易。

于 2011-10-12T16:30:41.507 回答
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;
}
于 2011-10-12T16:05:37.593 回答