基 class 是派生 class 的不明确基

Base class is an ambiguous base of derived class

我无法理解如何在多重继承情况下区分基础 class 的多个实例。在寻找解决方案时,我只找到了关于 virtual inheritance 的答案,但这根本没有解决我的问题,因为我不想在最后的 class 中有一个基础实例继承树。

在维基百科上,第一段指出:

Without virtual inheritance, if two classes B and C inherit from a class A, and a class D inherits from both B and C, then D will contain two copies of A's member variables: one via B, and one via C. These will be accessible independently, using scope resolution.

但我没有找到任何关于如何在我的情况下使用范围解析的信息。

至于我的任务,(强制和过于复杂的)class 层次结构是:

class Vehicle
{
    protected:
        unsigned long uPrice;
        char* szOwner; // for some reason, not allowed to use std::string in my homework...
    public:
        unsigned long GetPrice();
        // ...
}

class Trailer : public Vehicle
{
    protected:
        unsigned long uWid;
        unsigned long uHei;
        unsigned long uLen;
        unsigned long uMaxWeight;
    public:
        // ...
};

class Car : public Vehicle
{
    protected:
        unsigned long uWid;
        unsigned long uHei;
        unsigned long uLen;
        char* szBrand;
    public:
        // ...
};

class Trailer_Car : public Trailer, public Car
{
    private:
        unsigned long uTotalMass;
    public:
        // ...
};

正如我上面所说,我想要 Vehicle 的多个实例在 Trailer_Car 的实例中(一个用于 Car,一个用于 Trailer)。这完全适用于:

Trailer_Car c(/*...*/, 3500, 1200);
std::cout << c.Trailer_Car::Car::GetPrice() << "\n"; // prints 3500
std::cout << c.Trailer_Car::Trailer::GetPrice();  // prints 1200

但是,在我的代码中,我必须对一个非均匀数组(可以包含 4 个 classes 中的任何一个)进行排序,并将 Trailer_Car 转换为 Vehicle 结果是 error: 'Vehicle' is an ambiguous base of 'Trailer_Car'。示例:

Vehicle** Arr = new Vehicle*[N];
// ...

Arr[i] = static_cast<Vehicle*>(new Trailer_Car); // error: 'Vehicle' is an ambiguous base of 'Trailer_Car'

我该如何解决这个问题?我知道错误来自于 Arr[i] 不知道 Trailer_Car 指向哪个 Vehicle 但仍然没有想到 C++ 之类的东西。
由于我更习惯于 C,我只是将 Arr 设为 void**,尽管我不知道 C++ 中的实践有多好,我要求这样做以避免在 C++ 中执行 C。

您可以使用指针类型的中间转换来控制您得到的是重复基数class的哪个实例

Arr[i] = upcast<Car*>(new Trailer_Car);

Arr[i] = upcast<Trailer*>(new Trailer_Car);

我建议避免对应该是隐式转换的内容进行“真实转换”。它不会强迫编译器做愚蠢的事情然后闭嘴,而演员通常会这样做。

template<typename S, typename T> S upcast(const T& t) { return t; }

这样,这两行中的任何一行都会为您提供具有显式指定目标类型的隐式转换,然后是具有推断目标类型的隐式转换 (Vehicle*)。

请注意,在存储指向两个 Vehicle 子对象之一的指针的过程中,您还要选择排序逻辑将使用的数据。

此外,您不应使用 newdelete 手动管理动态内存,而应使用智能指针。您编写的一个或一个库...但遵循单一职责原则并且不要将内存管理与其他任何东西放在同一 class 中。