与 std::list 一起使用的指针上的接口类型转换的多重继承

Multi-inheritance with interfaces type casting on pointers for using with std::list

我来自 Java (OOP) 背景。我做了一个简单的class来说明我的问题:

#include <list>
#include <string>
#include <iostream>

// classes
class InterfaceA
{
public:
    virtual std::string functionA();
};

class InterfaceB
{
public:
    virtual std::string functionB();
};

class DerivedAB : public InterfaceA, public InterfaceB
{
public:
    std::string functionA()
    {
        return "I'm a A object";
    }

    std::string functionB()
    {
        return "I'm a B object";
    }
};

// functions
void doStuffOnListOfA(std::list<InterfaceA*> aElements)
{
    std::cout << "Print list of A" << std::endl;
    for (InterfaceA* const& a : aElements)
    {
        std::cout << a->functionA() << std::endl;
    }
};

int main()
{
    std::list<DerivedAB*> derivedABs;   
    doStuffOnListOfA(derivedABs);
    return 0;
}

我有两个简单的虚拟 classes InterfaceAInterfaceB 以及一个 class DerivedAB 多重继承了两个第一个虚拟 classes.

此外,我随后创建了一个 DerivedAB (std::list<DerivedAB *>) 的指针列表,并希望将此列表与旨在处理 InterfaceA 派生列表的函数一起使用对象。但是我得到一个错误:

(base)  ❮ onyr ★  kenzae❯ ❮ multi_inheritance_type_convertion❯❯ make
g++    -c -o main.o main.cpp
main.cpp: In function ‘int main()’:
main.cpp:54:32: error: could not convert ‘derivedABs’ from ‘std::__cxx11::list<DerivedAB*>’ to ‘std::__cxx11::list<InterfaceA*>’
     doStuffOnListOfA(derivedABs);                               

我显然有类型转换错误。我在 Stack Overflow 上阅读了很多关于 C++ 中的不同转换以及多重继承的文章,但我的大脑拒绝给我答案。


编辑:

我说错了:

"However I'm pretty sure such a code would work in Java..."

显然我遗漏了一个关于类型继承的重要概念...

C++ 与 Java!

大不相同

I have obviously a type casting error.

你是对的(也就是类型不匹配)! std::list 是一个标准模板容器,当您使用模板参数实例化时,它会为您提供具体类型。 也就是说,std::list<InterfaceA*> 不同于 std::list<DerivedAB *>

这正是编译器告诉你的:

error: could not convert 
from ‘std::__cxx11::list<DerivedAB*>’     ----> i.e. std::list<DerivedAB*>
to    ‘std::__cxx11::list<InterfaceA*>’   ----> i.e  std::list<InterfaceA*>
     doStuffOnListOfA(derivedABs);        ----> at the function call

你不能隐式地(即编译器不会)相互转换。

您需要将 derivedABs 的每个元素转换为基指针或(在您的情况下)将 doStuffOnListOfA 作为模板函数:

template<typename T>
void doStuffOnListOfA(std::list<T*> aElements)
{
    std::cout << "Print list of A" << std::endl;
    for (InterfaceA* a : aElements)
    {
        std::cout << a->functionA() << std::endl;
    }
};

为确保仅将以上内容用于 std::list<derived from InterfaceA and B>,您可以(可选)SFINAE 模板函数:

#include <type_traits> // std::is_base_of

template<typename T>
constexpr bool isBaseOfInterfaces = std::is_base_of_v<InterfaceA, T> && std::is_base_of_v<InterfaceB, T>;

template<typename T>
auto doStuffOnListOfA(std::list<T*> aElements) 
    -> std::enable_if_t<isBaseOfInterfaces<T>, void>
{
    // ... code
};

也就是说,

  • 你需要研究智能指针(如std::unique_ptr, std::shared_ptr)而不是使用原始指针(手动内存管理),通过它你可以巧妙地处理内存管理。
  • 您可能希望在基 类 中添加 virtual 析构函数以实现定义的行为。看这里了解更多:When to use virtual destructors?

这里是(the complete demo)