如何在C++中向函数传递“任何类型的数据”

6
假设我有一个名为Handler的类,它有一些子类,例如StringHandler、SomeTypeHandler、AnotherTypeHandler。类Handler定义了一个"handle"方法作为所有子类的公共接口。当然,不同的处理程序具有完全不同的"handle"逻辑。
因此,我需要做的是将任何值传递给handle方法。特定的类可以将"anything"转换为他们期望的类型。
基本上我需要的是像Java类Object一样的东西:D
我尝试的第一件事是使用void*,但显然你不能这样做B* someB = dynamic_cast(theVoidPointer),所以没什么运气。
我的第二个想法是使用boost::any。然而,使用boost::any的要求是该值必须可复制构造,而我的数据并非如此。
有什么想法可以让这个工作吗?
谢谢
编辑:请注意,我知道我可以使用一个没有成员的SomeData类,并让我的数据成为其子类,但我正在寻找一种更通用的方法,不需要我自己创建包装器类。

2
你确定你需要使用dynamic_cast,而不能使用reinterpret_cast吗? - Marc Bollinger
1
你也可以使用boost::any来存储指针,因此处理的类型不需要可复制构造。 - fdlm
5
我认为你应该退后一步,告诉我们你想达到什么目的,而不是你如何实现它。在我看来,你正在走进杂草丛中,用一个在Java中可能有效但在C ++中却是可怕滥用(实际上,在OO中非常可怕,但Java却接受)的想法。 - Jerry Coffin
@fdlm 我现在正在尝试。听起来是个不错的计划。也许你应该把它做成一个答案? - W. Goeman
1
退一步,退一步,再退一步。向上转型通常是设计不良的标志。类型切换(在开放集上)通常是设计不良的标志。 - Matthieu M.
显示剩余2条评论
5个回答

1
你可以定义一个基类,例如:
class BaseHandlerData {
   ...
};

然后派生出你的特定数据类,这些类由处理程序要求。
class StringData: public BaseHandlerData {
   ...
};

class SomeData: public BaseHandlerData {
   ...
};

然后您应该能够将BaseHandlerData*参数传递给handle方法,并使用类似以下的内容:

void handle(BaseHandlerData *data) {
    StringData* stringData = dynamic_cast<StringData*>(...);
    // handle your string data here ...
}

进行安全转换以匹配您期望的数据类型。

杰拉尔德


这是我在编辑中简要提到的详细内容。确实是一个好的解决方案,但我不想为此编写额外的类。我更愿意将其作为基本实用程序(如boost::any)。 - W. Goeman

1

好的,这里有一个简单的方法,使用boost::any来保存指向您的数据类型的指针。但是,请注意,boost::any会增加一些开销代码,稍微降低性能(在大多数情况下可以忽略不计)...考虑改用boost::spirit::hold_any,或者如果您不需要类型安全,则使用void*。

class Handler {
public:
    void handle( boost::any value ) { 
        do_handle( value );
    }
private:
    virtual void do_handle( boost::any& value ) = 0;
};

template<class T>
class HandlerBase : public Handler {
private:
    void do_handle( boost::any& value ) {
        // here you should check if value holds type T*...
        handle_type( *(boost::any_cast<T*>( value )) );
    }

    void handle_type( const T& value ) = 0;
};

class StringHandler : HandlerBase<std::string> {
private:
    void handle_type( const std::string& value ) {
        // do stuff
    }
};

现在,您可以编写许多处理程序类,从HandlerBase派生,而不必假定处理的类型具有共同的基类。

这是我使用的解决方案,除了模板化的HandlerBase。我把它留了下来。我只是让特定的处理程序转换为它们需要的类型。一旦我有多个相同数据类型的处理程序,我会考虑在它们之间放置模板化的基础。谢谢! - W. Goeman

1

0
你需要拥有一个名为DataObject的基类。所有数据类型(字符串,数字等)都是DataObject的子类。然后你可以像下面这样定义Handle:
void Handle(DataObject *dataObject);

这是一种更安全的实现你想要的功能的方式。为了让它变得更好,DataObject甚至可以知道它包含的数据类型。然后处理程序可以检查它们是否被发送了正确类型的数据。


这基本上是我在编辑中添加的内容。这似乎确实是一个不错的解决方案,但我正在寻找一种更通用的方法。如果其他解决方案行不通,我仍将把它保留在我的选项列表中。 - W. Goeman

-1

你可以做到

B* someB = static_cast<B*>(theVoidPointer);

@R.MartinhoFernandes和BertR,你们能否详细说明reinterpret、static和dynamic之间的区别?我认为reinterpret和static存在一些危险性。 - W. Goeman
@R. Martinho Fernandes:在C++11之前,reinterpret_cast确实可能导致未定义的行为,但是对于C++11来说,情况已经不再如此。好吧,看起来Stroustrup犯了同样的错误,所以我可能会犯更糟糕的错误:http://compgroups.net/comp.lang.c++.moderated/stroustrup-void-and-reinterpret_cast/68873 - BertR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接