gpt4 book ai didi

c++ - 通过多重私有(private)继承扩展类——这是一回事吗?

转载 作者:行者123 更新时间:2023-11-30 05:35:05 26 4
gpt4 key购买 nike

我正在尝试将现有功能封装在大量的类中,以便可以对其进行统一修改(例如互斥、优化、记录等)出于某种原因,我已经想到了(多个)私有(private)继承是可行的方法,但我找不到导致我得出该结论的原因。

问题是:我想做的事情的名称是什么,我在哪里可以看到它正确完成?

我认为这不是:

  • 装饰器:我看到的所有关于此模式的描述都包装了一个类,以提供从外部查看的额外方法。我想为内部提供功能(提取现有功能并添加其他功能。)
  • 接口(interface):这很接近,因为该功能有一个定义明确的接口(interface)(我想模拟一个用于测试的接口(interface)。)但是这个模式同样处理来自外部的 View 。

我也对其他选择持开放态度,但这里的大奖是找到一篇比我聪明得多的人写的关于它的文章(如 la Alexandrescu、Meyers、Sutter 等)

示例代码:

// Original code, this stuff is all over
class SprinkledFunctionality
{
void doSomething()
{
...
int id = 42;
Db* pDb = Db::getDbInstance(); // This should be a reference or have a ptr check IRL
Thing* pThing = pDb->getAThing(id);
...
}
}

// The desired functionality has been extracted into a method, so that's good
class ExtractedFunctionality
{
void doSomething()
{
...
int id = 42;
Thing* pThing = getAThing(id);
...
}

protected:
Thing* getAThing(int id)
{
Db* pDb = Db::getDbInstance();
return pDb->getAThing(id);
}
}

// What I'm trying to do, or want to emulate
class InheritedFunctionality : private DbAccessor
{
void doSomething()
{
...
int id = 42;
Thing* pThing = getAThing(id);
...
}
}

// Now modifying this affects everyone who accesses the DB, which is even better
class DbAccessor
{
public:
Thing* getAThing(int id)
{
// Mutexing the DB access here would save a lot of effort and can't be forgotten
std::cout << "Getting thing #" << id << std::endl; // Logging is easier
Db* pDb = Db::getDbInstance(); // This can now be a ptr check in one place instead of 100+
return = pDb->getAThing(id);
}
}

最佳答案

您可能会忽略的一项有用技术是非虚拟接口(interface) (NVI),这是 Sutter 在其关于虚拟性的著作中创造的。它需要稍微改变您看待它的方式,但旨在解决这些确切的问题。它还从内部解决了这些问题,也就是说,装饰器是关于从外部非侵入性地扩展功能的。

class Foo
{
public:
void something()
{
// can add all the central code you want here for logging,
// mutex locking/unlocking, instrumentation, etc.
...
impl_something();
...
}

private:
virtual void impl_something() = 0;
};

我们的想法是支持您的公共(public)接口(interface)使用非虚函数,但让它们调用在其他地方被覆盖的虚函数(具有私有(private)或 protected 访问权限)。这为您提供了通常通过继承获得的可扩展性,同时保留了中央控制(否则通常会丢失)。

现在 Bar 可以从 Foo 派生并覆盖 impl_something 以提供特定的行为。然而,您保留了 Foo 中的中央控制权,可以添加您喜欢的任何内容并影响 Foo 层次结构中的所有子类。

最初 Foo::something 甚至可能只调用 Foo::impl_something 做任何事情,但这里的值(value)是为将来添加提供的喘息空间任何你想要的中央代码——如果你低头查看一个代码库,它有大量直接依赖于虚拟函数的代码库,这可能会非常尴尬。通过依赖一个公共(public)非虚拟函数,该函数依赖于一个被覆盖的非公共(public)虚拟函数,我们获得了一个中间站点,我们可以在其中添加我们喜欢的所有中央代码。

请注意,这也可能有点矫枉过正。在 SE 中一切都可能过大,因为一个足够简单的程序实际上可能是最容易维护的,如果它只使用全局变量和一个大的 main 函数。所有这些技术都需要权衡取舍,但随着足够的规模、复杂性和不断变化的需求*,优点开始超过缺点。

* 我注意到您在另一个问题中写道,适合这项工作的正确工具应该具有零缺点,但一切往往都有缺点,一切都是权衡取舍。最终决定它是否是一个好的设计决策的是利弊是否​​大于利弊,并且远见卓识而不是事后诸葛亮来实现所有这些远非易事。

至于你的例子:

// What I'm trying to do, or want to emulate
class InheritedFunctionality : private DbAccessor
{
void doSomething()
{
...
int id = 42;
Thing* pThing = getAThing(id);
...
}
}

...这里的耦合比本示例所需的耦合要紧密得多。它可能比你所展示的更多,这使得私有(private)继承成为必要,但否则组合通常会在没有太多额外努力的情况下大大放松耦合,就像这样:

class ComposedFunctionality
{
...
void doSomething()
{
...
int id = 42;
Thing* pThing = dbAccessor.getAThing(id);
...
}
...

private:
DbAccessor dbAccessor;
};

关于c++ - 通过多重私有(private)继承扩展类——这是一回事吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33988733/

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