4

再会,

我不确定如何用一句话正确描述我正在询问的过程,所以请原谅标题。我正在寻找一种方法来确保基类和/或接口的用户会以非默认方式分配对象本身和其他对象会考虑的数据。所以我一直在做以下事情:

struct ExampleInterface {
    virtual void SomeMethod() = 0;
    virtual std::string WhatLooksLikeAGetterButIsNot() = 0;
};

这是一个真实世界的例子:

//So states can be "poped in and out".//
struct State
{
    //To retrive what the active state is called.//
    /*Code In Question--->*/virtual std::string RegardStateAs() = 0;/*<---Code In Question*/
    virtual void ExecuteState( VRGE::MDNode* metaData ) = 0;
};

这个想法是最终做一些事情,比如 A (如果有人从“更新”派生,这个选项允许试图阻止问题发生):

struct Update : public State
{
    //Yadda yadda...//
    /*Code In Question--->*/std::string RegardStateAs() {
                                return std::string{ "Update" };
                            }/*<---Code In Question*/
};

B(此选项不允许 A 所做的事情):

struct Update : public State
{
        //Yadda yadda...//
        //Not a good example, but the point gets across.//
        Update( std::string value ) {
            stateName = value;
        }
        /*Code In Question--->*/virtual std::string RegardStateAs() {
                                        return stateName;
                                 }/*<---Code In Question*/
            private: 
               std::string stateName;

};

我的问题是:这是好的还是坏的做法?

- - -编辑 - - -:

我无法访问可以编译它的编译器,但是有人向我指出,在这种情况下“覆盖”将是完美的,例如:

//So states can be "poped in and out".//
struct State
{
    //To retrive what the active state is called.//
    /*Code In Question--->*/virtual std::string RegardStateAs() = 0;/*<---Code In Question*/
    virtual void ExecuteState( VRGE::MDNode* metaData ) = 0;
};

struct Update : public State
{
    //Yadda yadda...//
    /*Code In Question--->*/std::string RegardStateAs() override {
                                return std::string{ "Update" };
                            }/*<---Code In Question*/
};
4

1 回答 1

3

正如其他人指出的那样,您的问题实际上是解决“覆盖”(在多态意义上),而不是“重载”。

假设您希望每个 State 子类(静态)都有一个固定标签,那么您的策略有效,但存在一些限制。为清楚起见,我将您的“RegardAsState”称为“ToString”。如果需要在基类State的构造函数中调用ToString,就会有问题。这是因为在执行基类构造函数时,尚未建立派生类(如 Update)的 ToString 的 v-table 条目。在 State 的析构函数中调用 ToString 也存在类似的问题。

另一种方法是简单地将状态标签实现为基类 State 中的 const std::string,并通过公共 get 访问器由 const std::string & 返回它。在消除 v-table 间接性和允许通过 const ref 返回方面,它的效率更高一些;它消除了 State 中的上述 ctor/dtor 问题。

即使上面的建议也不是最优的,因为如果每个不同的 State 子类的标签都相同,则无需将此作为实例方法。如果您想获得异国情调,您可以将 ToString 实现为静态(无状态)访问器。这可以通过一个鲜为人知的技巧来完成,即传递一个常量字符串作为模板参数,如下所示:

template<const std::string & label>
struct State
{
    static const std::string & ToString()
    {
        return label;
    }
};

extern const std::string UpdateLabel = "Update";
State<UpdateLabel> Update;

// Or, with a bit of help from the macro preprocessor
#define DEFINE_STATE(stateClass) \
extern const std::string stateClass##Label = #stateClass; \
struct stateClass##State : State<stateClass##Label> \
// continue with definition of stateClass##State ... {}

DEFINE_STATE(Sample)
{
    // implementation of SampleState
};
于 2013-04-26T22:04:35.190 回答