0

类 StructComponent 的构造函数根据传入的 info 对象的类型,采用不同的逻辑来初始化其成员变量。这里我使用强制转换将传入参数转换为正确的子类对象。

class StructComponent
{
public:
    StructComponent(const ClassA& info)
    {
        if (info.getType() == CLASS_B)
        {
            const ClassC& classC = dynamic_cast<const ClassC&> info;
            ...
            apply a different logic for ClassB and init member accordingly
        } else if (info.getType() == CLASS_C) {
            apply a different logic for others
            ...
        } else {
                    apply default
            }
    }
}

class ClassA
{
public:
    ClassA(...)
    {
        m_shp = CreateStructComponent();
    }   
    virtual boost::shared_ptr<StructComponent> CreateStructComponent()
    {
        return boost::shared_ptr<StructComponent> (new StructComponent(*this));     
    }

    ...
    int getType() const { return CLASS_A; }

protected:
    boost::shared_ptr<StructComponent> m_shp;
}

class ClassB : public ClassA
{
public:
    ...

    virtual boost::shared_ptr<StructComponent> CreateStructComponent()
    {
        return boost::shared_ptr<StructComponent> (new StructComponent(*this));     
    }   
    ...
    int getType() const { return CLASS_B; } 
}

class ClassC : public ClassA
{
public:
    ...

    virtual boost::shared_ptr<StructComponent> CreateStructComponent()
    {
        return boost::shared_ptr<StructComponent> (new StructComponent(*this));     
    }   
    ...
    int getType() const { return CLASS_C; } 
}

Q1> 代码是否正确忽略了潜在的设计问题?

Q2>假设ClassA的所有子类都有相同的函数CreateStructComponent的实现体。有没有一种方法可以节省空间而不是重复执行以下相同的代码:

return boost::shared_ptr<StructComponent> (new StructComponent(*this));

Q3> 有没有更好的设计可以使用?例如,有没有一种方法可以忽略 StructComponent 中的强制转换?

4

2 回答 2

2

在执行类的构造函数时A,对象的类型是A. 因此将始终调用基本实现。因此,您可以省去重新键入实现的麻烦。

此代码设计错误;并且设计不正确的代码永远不会正确,至少在“正确”一词的通常含义中是这样。

如果 C++ 规则不适合您,则没有理由使用构造函数进行初始化。只需将其设为方法,调用 thing Initialize,您就可以调用任何您想要的虚拟方法Initialize,并获得您所期望的效果。

于 2012-07-31T20:07:34.600 回答
2

1) 不,它不正确,至少,它没有达到您的预期。它在 的构造函数中调用了一个虚函数,该函数ClassA将始终调用ClassA::CreateStructComponent()而不是调用派生类中的覆盖函数,因为当ClassA构造函数运行时,动态类型是ClassA. 出于同样的原因,在构造函数中StructComponent调用getType()将始终解析为ClassA::getType().

2)有很多方法可以解决这个问题。您可以将代码放在模板中,因此它取决于类型,或者您可以通过在不同的地方进行初始化来摆脱重复代码的需要。

3)为什么不简单地给StructComponent重载的构造函数,一个接受ClassB,一个接受ClassC,另一个接受ClassA

再一次,一个更好的解决方案可能是摆脱StructComponent构造函数并具有ClassA,ClassBClassC显式地进行初始化,以便每种类型按照它想要的方式对其进行初始化。如果初始化依赖于创建它的类型,则初始化不属于StructComponent构造函数。目前你有一个循环依赖,StructComponent需要知道所有使用它的类型,所有使用它的类型都需要知道StructComponent. 这通常是设计存在问题的迹象,所有类都紧密耦合在一起。StrictComponent如果对其他类型一无所知,那就更好了。

无论如何,这是一个可能的解决方案,展示了一种将正确类型传递给StructComponent不重复代码的方法,但我认为这不是一个好的设计。请注意,Structcomponent构造函数传递的是 NULL,因此它可以根据类型做不同的事情,但不能访问它传递的对象。

class StructComponent
{
public:
    explicit StructComponent(const ClassA*)
    { /* something */ }

    explicit StructComponent(const ClassB*)
    { /* something else */ }

    explicit StructComponent(const ClassC*)
    { /* something completely different */ }
};

class Base
{
protected:
  template<typename T>
    explicit
    Base(const T*)
    : m_shp( boost::make_shared<StructComponent>((T*)NULL) )
    { }

    boost::shared_ptr<StructComponent> m_shp;
};

class ClassA : virtual public Base
{
public:
    ClassA() : Base(this) { }
};

class ClassB : public ClassA
{
public:
    ClassB() : Base(this) { }
};

class ClassC : public ClassA
{
public:
    ClassC() : Base(this) { }
};

这是另一种完全不同的方法,没有虚拟基础黑客,仍然删除重复的代码,并允许StructComponent访问传递给它的对象(我认为这是一个坏主意):

class StructComponent
{
public:
    explicit StructComponent(const ClassA& a)
    { /* something */ }

    explicit StructComponent(const ClassB& b)
    { /* something else */ }

    explicit StructComponent(const ClassC& c)
    { /* something completely different */ }
};

class ClassA
{
public:
    ClassA() : m_shp( create(*this) ) { }

protected:
    struct no_init { };

    explicit
    ClassA(no_init)
    : m_shp()
    { }

    template<typename T>
      boost::shared_ptr<StructComponent> create(const T& t)
      { return boost::make_shared<StructComponent>(t); }

    boost::shared_ptr<StructComponent> m_shp;
};

class ClassB : public ClassA
{
public:
    ClassB()
    : ClassA(no_init())
    { m_shp = create(*this); }
};

class ClassC : public ClassA
{
public:
    ClassC()
    : ClassA(no_init())
    { m_shp = create(*this); }
};

这是另一个选择,这次没有循环依赖,将不同的初始化代码移动到它所属的位置:

struct StructComponent
{
  StructComponent() { /* minimum init */ }
};

class ClassA
{
public:
    ClassA() : m_shp( createA() ) { }

protected:
    struct no_init { };

    explicit
    ClassA(no_init)
    : m_shp()
    { }

    boost::shared_ptr<StructComponent> createA()
    {
      // something
    }

    boost::shared_ptr<StructComponent> m_shp;
};

class ClassB : public ClassA
{
public:
    ClassB()
    : ClassA(no_init())
    { m_shp = createB(); }

private:
    boost::shared_ptr<StructComponent> createB()
    {
      // something else
    }
};

class ClassC : public ClassA
{
public:
    ClassC()
    : ClassA(no_init())
    { m_shp = createC(); }

private:
    boost::shared_ptr<StructComponent> createC()
    {
      // something completely different
    }
};
于 2012-07-31T20:16:38.147 回答