在派生类中使用/存储派生成员以及存储基本成员

时间:2016-02-10 22:04:12

标签: c++ c++11 inheritance smart-pointers raii

我经常遇到的情况是拥有一组类BaseDerived,其中Base类拥有基类成员BaseMember的所有权,Derived类具有指向同一对象的引用或指针,但是为DerivedMember

例如,一个UI面板类,它包含具有某些特殊控制功能的特定类型控件的特定实例,继承自包含常规控件并具有通用控件功能的通用类。

首先,假设BaseMember继承了DerivedMemeber

如果不使用智能指针,我可能会这样做:

class Base
{
protected:
    // receive ownership but only because we say so,
    // someone else can still try to delete as it's "just a pointer"
    Base(BaseMember* _bmember):
        bmember(_bmember)
    {}

public:
    virtual ~Base()
    {
        // perform an owner's duty
        delete bmember;
    }

    // functions that might be based on BaseMember + other base state
    void SetMemberId(....) 
    {
        bmember->SetId(baz);
    }

private:
    int baz;
    BaseMember* bmember; //owned, but not smartly
}

class Derived: public Base
{
public:
    Derived(DerivedMember* _dmember):
        Base(_dmember),
        dmember(_dmember)
    {}

    // functions that only make sense for Derived + Derived/Base state
    void SetDerivedFrobulation()
    {
        // only a DerivedMember has frobulation, so only
        // Derived allows users to access it
        dmember->setFrobulation(foo);
    }

private:
    int foo; // some state
    DerivedMember* dmember; // no ownership here
}

使用智能指针(C ++ 11及更高版本,特别是在这种情况下,我并不真正关心旧的C ++),我很想做类似的事情,永远不要让Base/DerivedMember对象如果有一个不方便的例外,那么它可能会泄漏到愚蠢的指针区域。

class Base
{
protected:
    // receive ownership
    Base(std::unique_ptr<BaseMember> _member):
        member(std::move(_member))
    {}

    virtual ~Base()
    {}

public:
    // public access functions here as before

private:
    std::unique_ptr<BaseMember> member;
}

class Derived: public Base
{
public:
    // pass the ownership down by unique_ptr
    Derived(std::unique_ptr<DerivedMember> _dmember):
        Base(std::move(_dmember)),
        dmember(_dmember.get()) // _dmember is moved! SEGFAULT if access dmember later!
    {}

    // public access functions here as before

private:
    // handy handle to the derived class so we don't need to downcast the base (or even access it!)
    DerivedClass* dmember
}

正如我在那里所指出的那样,你不能偷看&#34;偷看&#34;来自DerivedMember构建器的Derived类,因为在unique_ptr查看之前moveDerived d。

我可以看到一个解决方案,在protected构造函数中提供对BaseMemberstatic_cast DerivedMember Derived Base的{​​{1}}访问权限。 Base构造函数完成了),但这似乎是一种丑陋的方式来获取访问我们让我们的手指滑过的变量!

另一种方式可能是Base的每个继承者拥有指针,而base只是获得一个哑指针。在这种情况下,Base析构函数无法访问该成员,因为它已经消失了。它也会不必要地复制所有权逻辑。

我认为:

  • 这是反模式的症状,整个Derived / BaseMember / DerivedMember / DataInterpreter系统的设计并不是一种好的做法。
  • 我错过了一个技巧,并且有一个干净的方法可以做到这一点,而不会弄乱智能指针,使泄漏成为可能,或添加功能,暴露界面或投射过多。

这是一个很好的重复使用模式,还是应该在其他地方寻找?

扩展用例(编辑)

在核心库中,我有一个班级TextInterpreter,它显示了一些解释&#34;数据 - 可以是字符串,图像等。然后由string(其中包含DataDisplayPanel继承。

然后我有一个TextInterpreter类,它代表一个用于以抽象意义显示的UI。确切地说,此面板中的内容将取决于所使用的解释器:TextDisplayPanel应该获得一个文本输入字段并说出一个按钮来设置一些文本显示选项,并在DataAggregatePanel中处理,其中包含& #34;特别&#34;了解口译员的文本方面。

然后有DataDisplayPanels组合了多个std::vector<std::unique_ptr<DataDisplayPanel> >并提供了一些影响所有显示的全局设置(通过虚拟功能),并管理wxDataAggregatePanel中的面板。这个聚合类根本不处理任何派生类,任何函数都是多态的,并在基类中定义。

在应用程序(依赖于核心库)中,这些类被扩展(通过继承或组合,无论哪个更有意义)。例如,如果应用程序是WX GUI,我可能wxTextDisplayPanel包含wxPanels(和其他),所有这些都是wxTextDisplayPanel。在这种情况下,wxTextEntry可能拥有TextInterpreter并拥有或继承TextInterpreter并使用其String s = "text string"; Random rand = new Random(); int randomIndex = rand.nextInt(s.length());//returns a random number between 0 and the index of the last character of the string System.out.println(s.charAt(randomIndex)); 特定方法的知识来填充文本框用一根绳子。

1 个答案:

答案 0 :(得分:5)

您可以使用委托构造函数:

class Derived: public Base
{
public:

    Derived(std::unique_ptr<DerivedMember> _dmember):
        Derived(_dmember, _dmember.get())
    {}

    // public access functions here as before
private:
 Derived(std::unique_ptr<DerivedMember>& _dmember, DerivedMember* ptr):
        Base(std::move(_dmember)),
        dmember(ptr)
    {}
private:
    // handy handle to the derived class so we don't need to downcast the base (or even access it!)
    DerivedClass* dmember
};