如果一个类继承具有相同功能的多个类,那么如何在不手动指定每个类的情况下调用每个继承的类的功能呢?
示例代码如下:
#include <cstdio>
class Interface1
{
public:
virtual ~Interface1() = default;
void foo()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
};
class Interface2
{
public:
virtual ~Interface2() = default;
void foo()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
};
class ObjectWithoutTemplate : public Interface1, Interface2
{
public:
void foo()
{
// How do I write the code to call each InterfaceX's foo() here
// without manually specify each class?
Interface1::foo();
Interface2::foo();
// The desired code looke like
// for each interface in Interfaces {
// interface::foo()
// }
}
};
template <class... Interfaces>
class ObjectWithTemplate : Interfaces...
{
public:
void foo()
{
// It does not compile if the template does not inherit Interface[1|2]
Interface1::foo();
Interface2::foo();
// The desired code looke like
// for each interface in Interfaces {
// interface::foo()
// }
}
};
int main()
{
ObjectWithoutTemplate objWithout;
ObjectWithTemplate<Interface1, Interface2> objWith;
objWithout.foo();
objWith.foo();
return 0;
}
对于ObjectWithoutTemplate
,我可以通过手动指定接口来调用接口的foo()
:
Interface1::foo();
Interface2::foo();
但是对于ObjectWithTemplate
的{{1}},考虑到会有foo()
,{{1},我该如何编写代码来调用每个继承的接口的foo()
}。
答案 0 :(得分:4)
假设您不希望重复任何碱基(并且没有碱基彼此继承),则可以执行此操作;
template <class FirstInterface, class... Interfaces>
class ObjectWithTemplate : public FirstInterface, public ObjectWithTemplate<Interfaces...>
{
public:
void foo()
{
FirstInterface::foo();
ObjectWithTemplate<Interfaces...>::foo();
};
};
// partial specialisation
template<class LastInterface>
class ObjectWithTemplate<LastInterface> : public LastInterface
{
public:
void foo()
{
LastInterface::foo();
};
};
类型的对象
ObjectWithTemplate<Interface1, Interface2> object;
实际上具有Interface1
和ObjectWithTemplate<Interface2>
作为基类。 ObjectWithTemplate<Interface2>
依次将Interface2
作为基类。
如果您重复碱基,或者使用两个碱基共享另一个碱基,例如
ObjectWithTemplate<Interface1, Interface1> object;
ObjectWithTemplate<Interface1, SomethingDerivedFromInterface1> object2;
然后,由于歧义,代码将无法编译。
答案 1 :(得分:2)
受Generating one class member per variadic template argument的启发,使用std::tuple<>
使其有效。
这不是完美的,因为它增加了二进制文件的大小,但可以正常工作。
template <class... Interfaces>
class ObjectWithTemplate : public Interfaces...
{
public:
std::tuple<Interfaces...> interfaces;
void foo()
{
// The size becomes 8 * num-of-inherited-classes
printf("sizeof(interfaces)=%zu\n", sizeof(interfaces));
std::apply([&](auto&&... args) {
(static_cast<decltype(args)>(*this).foo(), ...);
},
interfaces);
}
};
答案 2 :(得分:1)
Folding expressions在这里有帮助:
template <class... Interfaces>
class ObjectWithTemplate : public Interfaces...
{
public:
void foo()
{
(Interfaces::foo(), ...);
}
};
对于C ++ 11 / C ++ 14版本,它也可以完成,但是比较冗长。