C++ 相互 header 包含和前向声明

C++ Mutual header inclusion and forward declarations

我如何允许两个 class 相互包含,以便它们可以从一个转换为另一个。

Car.hpp

#ifndef CAR_HPP
#define CAR_HPP

#include "Truck.hpp"
class Car
{
public:
    Car(int weight) : weight(weight) {}
    Car(Truck data) : weight(ConvertFromTruck(data)) {}

private:
    int weight;
    int ConvertFromTruck(Truck data)
    {
        ... //in real life there would be a lot more to transfer than just weight.
    }
}
#endif //CAR_HPP

Truck.hpp

#ifndef TRUCK_HPP
#define TRUCK_HPP

#include "Car.hpp" //Obviously won't be included because of the CAR_HPP include guard
class Truck
{
public:
    Truck(int weight) : weight(weight) {}
    Truck(Car data) : weight(ConvertFromCar(data)) {}

private:
    int weight;
    int ConvertFromCar(Car data)
    {
        ...//in real life there would be a lot more than just weight
    }
}
#endif //TRUCK_HPP

Main.cpp

#include "Car.hpp"
#include "Truck.hpp"

int main()
{
    Car newCar(42);
    Truck newTruck(newCar);

    return 0;
}

所以显然 Truck.hpp 不能真正包含 Car.hpp 因为 CAR_HPP 已经定义了。另外,Truck.hpp 不能前向声明 class Car; 因为 Truck(Car data)... 需要一个完整的类型,而前向声明的 class 不是一个完整的类型。

看起来像这样:Forward declaration being ignored?但是没有答案。

本主题声明不相互包括headers。 Forward Declarations and Includes

我会尽量避免这种情况,但我怎样才能获得可以接收卡车并正确转换的汽车和可以接收汽车并正确转换的卡车?

有什么方法可以使用: operator Car() { ... }operator Truck() { ... } 以便可以将汽车铸造成卡车,反之亦然?

在声明中

int ConvertFromTruck(Truck data)

Truck 需要是 complete 类型,这意味着编译器必须可以使用 Truck 的 class 定义。这就是你的问题。

幸运的是有一个解决方案:通过const引用传递Truck

int ConvertFromTruck(const Truck& data)

这里编译器只需要 incomplete 类型用于 Truck,而 forward class 声明 #include 就足够了。这在 run-time 上也非常优越,因为您在函数运行时没有获取 Truck 的值副本(尽管编译器可能会优化该副本)。

对构造函数(即 Car(const Truck& data))和 Truck class 执行相同的操作。

请注意,我使用 const 参考而不是非 const 参考有两个原因 (i) 你 不想 能够修改传递的对象,并且 (ii) 匿名临时 可以绑定到 const 引用。