根据不同的类型,联盟成员仅在一个类中

Union members exclusively in a class depending on different types

本文关键字:一个 类型 联盟成员      更新时间:2023-10-16

我正在实现一个类,其中每个实例化都有一个句柄,该句柄将完全依赖于成员type。不同的类型与不同的句柄相关联。

enum class Type {
TypeA, TypeB, TypeC;
};
class HandleA { ... };
class HandleB { ... };
class HandleC { ... };
class Foo {
public:
Type type;
std::unique_ptr<HandleA> handleA;
std::unique_ptr<HandleB> handleB;
std::unique_ptr<HandleC> handleC;
};

理想情况下,如果类型为TypeA,则存在handleA;如果类型为TypeB,则存在handleB;如果类型是TypeC,则存在handleC。然而,我认为应该有一个更好的设计模式。否则,我的类型越多,类Foo中占用的unique_ptr就越多。我知道union可能是一个很好的解决方案,但我想知道是否存在更具可扩展性的c++c++11解决方案。由于Foo可能以虚拟的方式用于其他派生类,这些派生类将采用不同的构造函数,所以我不想寻找模板化的解决方案。

我一直在研究需求,发现这里要解决的基本问题是:如何在运行时选择类型。

其他一切都可以用一点模板魔法来解决——在Foo本身不应该是模板的情况下,这种魔法就失败了。

那么,任何克服这个问题的技巧(我们可以用成员函数指针做一些令人惊叹的事情)似乎只会让我们重新实现已经免费提供的VTable间接虚拟函数。在这种考虑下,我倾向于遵循@RobK:的评论

#include <iostream>
#include <memory>
#include <string>
enum class Type { TypeA, TypeB, TypeC };
class Handle
{
public:
// virtual ~Handle() = default; // if any subclass is not empty
virtual std::string sing() const = 0; // purely virtual function
};
class HandleA : public Handle { public: std::string sing() const { return "Aaha"; } };
class HandleB : public Handle { public: std::string sing() const { return "Behe"; } };
class HandleC : public Handle { public: std::string sing() const { return "Cehe"; } };
class Foo
{
Type type;
std::unique_ptr<Handle> handle;
public:
constexpr Foo(Type newType) : type{newType}, handle()
{
switch(newType) // establishes the mapping between Type and Handle-subclass
{
case Type::TypeA: this->handle.reset(new HandleA()); return;
case Type::TypeB: this->handle.reset(new HandleB()); return;
case Type::TypeC: this->handle.reset(new HandleC()); return;
}
}
// virtual function call automatically resolves to used subclass
void showHandle() const { std::cout << this->handle->sing() << std::endl; }
};
int main()
{
Foo fooA(Type::TypeA);
Foo fooB(Type::TypeB);
Foo fooC(Type::TypeC);
fooA.showHandle();
fooB.showHandle();
fooC.showHandle();
}

请注意,当以这种方式使用不完整的类型(如我的句柄)时,需要记住以下几点:

  1. 如果任何子类定义了自己的非静态成员对象,Handle和所有子类都必须接收一个声明的虚拟析构函数。
    • 如果没有,对此类子类的对象的销毁是不完整的,并且会泄漏内存
    • 就像Handle中注释掉的析构函数一样,这些可以是默认值
  2. 不重写纯虚拟函数(如我的Handle::sing)然后调用它将立即终止程序
相关文章: