简体   繁体   English

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

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

I come from Java (OOP) background.我来自 Java (OOP) 背景。 I made a simple class to illustrate my problem:我做了一个简单的 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;
}

I have two simple virtual classes InterfaceA and InterfaceB and a class DerivedAB that multi-inherits the two first virtual classes.我有两个简单的虚拟类InterfaceAInterfaceB以及一个 class DerivedAB ,它多重继承了前两个虚拟类。

Furthermore, I then create a list of pointers of DerivedAB ( std::list<DerivedAB *> ) and wish to use this list with a function designed to work on a list of InterfaceA -derived objects.此外,我随后创建了DerivedAB的指针列表 ( std::list<DerivedAB *> ),并希望将此列表与设计用于处理InterfaceA派生对象列表的 function 一起使用。 But I get an error:但我得到一个错误:

(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);                               

I have obviously a type casting error.我显然有类型转换错误。 I have read many articles on Stack Overflow about the different casting in C++ as well as on Multi-Inheritance, but my brain refuses to give me the answer.我在 Stack Overflow 上阅读了很多关于 C++ 以及多重继承中的不同转换的文章,但我的大脑拒绝给我答案。


Edits:编辑:

I said an erroneous statement:我说了一个错误的说法:

"However I'm pretty sure such a code would work in Java..." “但是我很确定这样的代码可以在 Java 中工作......”

Apparently I'm missing an important concept about type inheritance...显然我错过了一个关于类型 inheritance 的重要概念......

C++ is far different from Java! C++ 和Java相差甚远!


I have obviously a type casting error.我显然有类型转换错误。

You are right about this (aka. type mismatch)!你是对的(又名。类型不匹配)! The std::list is a standard template container which gives you a concrete type, when you instantiate with a template argument. std::list是一个标准模板容器,当您使用模板参数实例化时,它会为您提供具体类型。 That means, the std::list<InterfaceA*> is different from std::list<DerivedAB *> .这意味着, std::list<InterfaceA*>不同于std::list<DerivedAB *>

This is exactly the compiler tells you:这正是编译器告诉你的:

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

You can not implicitly(ie compiler will not) convert to one another.您不能隐式(即编译器不会)相互转换。

You need to cast each element of the derivedABs to base pointers or (in your case) make the doStuffOnListOfA as template function:您需要将derivedABs的每个元素转换为基指针或(在您的情况下)将doStuffOnListOfA作为模板 function:

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;
    }
};

To make sure that, one use the above only for std::list<derived from InterfaceA and B> , you may can (optionally) SFINAE the template function:为确保仅将上述内容用于std::list<derived from InterfaceA and B> ,您可以(可选) SFINAE模板 function:

#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
};

That being said,话虽如此,

  • You need to look into the smart pointers (such as std::unique_ptr , std::shared_ptr ) rather than using raw pointers (manual memory management), by which you can handle the memory management smartly.你需要查看智能指针(如std::unique_ptrstd::shared_ptr )而不是使用原始指针(手动 memory 管理),通过它你可以巧妙地处理 memory 管理。
  • You might want to add the virtual destructor in your base classes for a defined behavior.您可能希望在基类中为定义的行为添加virtual析构函数。 See here for more: When to use virtual destructors?有关更多信息,请参见此处: 何时使用虚拟析构函数?

Here is ( the complete demo )这是完整的演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM