与 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 InterfaceA
和 InterfaceB
以及一个 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)
我来自 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 InterfaceA
和 InterfaceB
以及一个 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)