gpt4 book ai didi

c++ - 在具有存储基成员的基类的派生类中使用/存储派生成员

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:33:54 27 4
gpt4 key购买 nike

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

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

首先说BaseMemberDerivedMemeber 继承.

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

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
}

正如我在那里指出的那样,您不能“偷看” DerivedMember Derived 中的类构造函数,因为 unique_ptrmove d离开之前Derived进去看看。

我可以通过提供 protected 来找到解决方案访问 BaseMemberstatic_cast回到DerivedMemberDerived构造函数(即在 Base 构造函数完成之后),但这似乎是一种丑陋的方式来重新访问我们从手指间溜走的变量!

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

我认为:

  • 这是反模式和整体设计的症状 Base/Derived/BaseMember/DerivedMember系统不是好的做法。
  • 我错过了一个技巧,有一种干净的方法可以做到这一点,而不会弄乱智能指针并导致泄漏成为可能,也不会添加函数并暴露接口(interface)或过度转换。

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

扩展用例(编辑)

在核心库中,我有一个类 DataInterpreter显示数据的“某种解释”——可以是字符串、图像等。然后由 TextInterpreter 等继承。它呈现一个 string .

然后我有一个 DataDisplayPanel类代表了一段抽象意义上的展示UI。该面板中的确切内容取决于所使用的解释器:a TextInterpreter应该得到一个文本输入字段并说出一个按钮来设置一些文本显示选项,这在 TextDisplayPanel 中处理。 ,它对解释器的文本方面具有“特殊”知识。

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

在应用程序(依赖于核心库)中,这些类被扩展(通过继承或组合,以更有意义的为准)。例如,如果应用程序是 WX GUI,我可能有 wxDataAggregatePanel其中包含 wxTextDisplayPanel (和其他人),所有这些都是 wxPanels .在这种情况下,wxTextDisplayPanel可能拥有 wxTextEntry并拥有或继承TextInterpreter并利用其关于 TextInterpreter 的知识用字符串填充文本框的具体方法。

最佳答案

你可以使用委托(delegate)构造函数:

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
};

关于c++ - 在具有存储基成员的基类的派生类中使用/存储派生成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35326858/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com