繁体   English   中英

C ++:如何对同一数据类使用不同的方法实现?

[英]C++: How can I use different implementation of methods with the same data class?

背景:我所涉及的程序的各个模块处理的是对象的相同组合,这些对象以聚合结构分组在一起。 对对象的组合施加了众所周知的不变量,所有模块都充分尊重了这些不变量。 每个模块都是由专门的团队开发的,每个团队都需要使用其特定于域的自定义方法来处理对象的组合。

示例:为了给您一个切实的想法,请想象一个序列容器类。 容器的核心在所有用户中都是相同的:它由用于存储,大小/容量和分配器的数据成员组成。 但是方法集,合同和这些方法的主体可能相差很大。 一个模块可以实现std风格的操作,另一个模块可以将所有操作实现为nothrow方法,而另一个模块可以坚持使用其私有检查的迭代器; 一些对性能要求严格的模块要禁止所有复制操作,而另一个模块却只能复制。...这些要求在任何给定模块的每个特定领域中都是合理的。

推测:因此,不可能提供一个可以满足所有客户团队需求的单一非冗余方法集-有些团队的要求是相互排斥的。 只提供所有模块通常需要的那些方法是没有用的,因为唯一的共同部分可能是析构函数。 将所有方法的所有可能的实现放在一起也不是一件好事:可维护性和稳定性差,接口混乱而,肿,许多名称冲突,许多跨模块依赖性。

问题:要让多个独立的实现对同一组数据成员进行操作,我必须具有哪些选择?

我尝试过的事情:到目前为止,我所看到的解决方案并不十分理想,我对其中任何一个都不完全满意。 我将在答案中列出它们,三种方法一一列出。

对于我自己的问题,可能有一种不太理想的解决方案:

1.不用理会方法,而要拥有独立的功能。

struct CoreData
{
    int   m_x;
    ~CoreData();
};

void TeamA_init(CoreData& data);
void TeamA_push_back(CoreData& data, Whatever args);
Iter TeamA_begin(CoreData& data);

bool TeamB_init(CoreData& data, Other args);
bool TeamB_push_back(CoreData& data, Whatever args);
X* TeamB_begin(CoreData& data);

//---------------------  Usage:
void ServiceOfTeamA::CallServiceOfTeamB(ServiceOfTeamB* srv)
{
    CoreData     d;
    TeamA_init(d);
    srv->Process(&d);
    TeamA_begin(d);
}

void ServiceOfTeamB::Process(CoreData* d)
{
    TeamB_push_back(*d, 567);
}

-我对这种方法不满意的是语法不友好,没有RAII和所有数据成员都是公开的。 那是C,不是C ++。

+从好的方面来说,这种方法提供了无限的定制可能性。 为任务选择正确的功能没有任何限制。 没有内存开销,没有运行时开销(也就是说,从技术上讲,编译器具有与那些自由函数作为方法相同的内联和优化机会)。

对于我自己的问题,可能有一种不太理想的解决方案:

2.具有一组通过引用对核心数据的外部实例进行操作的类。

struct CoreData
{
    int   m_x;
    ~CoreData();
};

class TeamA
{
public:
    // Allocates a new instance and owns it.
    TeamA();

    // Attaches an external instance without assuming ownership.
    TeamA(CoreData& ext);

    // Release the core, if must.
    ~TeamA();

    void push_back(Whatever args);
    Iter begin();
    CoreData& GetCore();

private:
    CoreData*     m_core;
    bool               m_doIOwnThatCore;
};

class TeamB
{
public:
    TeamB();
    TeamB(CoreData& ext);
    ~TeamB();

    int push_back(Whatever args);
    CoreData& GetCore();

private:
    CoreData*     m_core;
    bool               m_doIOwnThatCore;
};

//---------------------  Usage:
void ServiceOfTeamA::CallServiceOfTeamB(ServiceOfTeamB* srv)
{
    TeamA        d;
    srv->Process(d.GetCore());
    d.begin();
}

void ServiceOfTeamB::Process(CoreData* core)
{
    TeamB        d(core);
    d.push_back(567);
}

-我不喜欢这种方法,因为它在内存使用和性能方面略有悲观。 语法还使TeamA和TeamB类型的对象看起来像值,而实际上它们具有引用语义。

+好消息是,这种方法为调用提供了更好的C ++语法(但仍然有丑陋的GetCore()),并且符合RAII。

对于我自己的问题,可能有一种不太理想的解决方案:

3.将代码扔在事实上定义的reinterpret_cast行为上。

// This is a standard layout class.
// It is the only class with data members;
// derived classes never append new data members.
class CoreData
{
public:
    // Could be either explicit conversion function
    // or implicit conversion operator.
    template <typename Final>
    // requires <LayoutCompatibleWithCore Final>
    Final& As()
    {
        return reinterpret_cast<Final&>(*this);
    }

protected:
    ~CoreData();

    int      m_x;
};

// No extra data members appended. No extra invariants imposed.
// This class is also a standard layout type,
// fully layout-compatible with CoreData.
class TeamA : public CoreData
{
public:
    void push_back(Whatever args);
    Iter begin();
};

class TeamB : public CoreData
{
public:
    bool push_back(Whatever args);
    X* begin();
};

//---------------------  Usage:
void ServiceOfTeamA::CallServiceOfTeamB(ServiceOfTeamB* srv)
{
    TeamA        d;
    srv->Process(&d);
    d.begin();
}

void ServiceOfTeamB::Process(CoreData* core)
{
    TeamB&       d = core->As<TeamB>();
    d.push_back(567);
}

-但是,这些技巧在标准中是非法的。 因此,我也必须拒绝这种方法。

+如果这是合法的,那么它将提供三种语言中最好的语法,该语法清楚地显示了参考语义,并且具有RAII并且没有悲观化。

PS这种方法的无效性使我失望。 布局兼容性的整个方面似乎都提供了在ABI兼容进程或共享组件之间传递数据的能力。 太糟糕了,它不允许在同一应用程序的各个部分之间传递数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM