gpt4 book ai didi

c++ - 多重继承。这个实现 `+=` 的继承模型背后的想法是什么?

转载 作者:太空狗 更新时间:2023-10-29 20:35:53 25 4
gpt4 key购买 nike

对于 C++ 类,我试图设计一个处理二进制操作的类层次结构 +=-= .所需的层次结构(每个问题要求)如下所述。我们有两个类(class) AdditionSubtraction .这些是类的基类 Binops .然后一个类Operations继承自 Binops .所以图表看起来像这样

       Operations
|

Binops
| |
| |
+---+ +---+
↓ ↓
Addition Subtraction

这里 BinopsOperations的好友类.需要以下成员函数: Operations实现私有(private)函数
void add(Operations const &rhs);
void sub(Operations const &rhs);

和类(class) Addition需要实现
Addition::operator+=(Operations const &rhs)

同样对于 Subtraction类(class)。

我对这个设计的实现以及它背后的想法都有疑问。

在我看来,一旦这个框架准备好,另一个类,例如 Matrix类可以从 Operations 继承类然后我们制作 Matrix Operations的 friend 所以 Matrix可以使用 +=等等。然后我们只需要实现 add函数在 Operations+=然后操作将适用于 Matrix类(class)。但是为什么我们不简单地实现 +=运算符(operator)在 Operations甚至 Matrix ?也许这个想法是我们也可以定义 =运算符(operator)在 Addition使用 add功能 Operations ,以便在实现后 add , 两者 +=+一口气工作。

从实现的角度来看: += 的返回类型应该是什么?在 Addition ?我相信应该是 Operations ,然后是 Addition类头应该包含 Operations导致循环依赖的 header 。

此外,对于 Addition能够使用 add来自 Operations , 有没有什么办法可以不用做 Addition Operations的 friend 也?我不认为简单地制作 Addition Binops的 friend 就足够了,因为友元不是可传递的。

抱歉问了这么长的问题。提前感谢您的任何见解!

最佳答案

看起来这些类名有点不对劲。我的通灵解码是 AdditionHasAddition .所以我们有 HasOperations继承自 HasBinOps ,它继承自 HasAdditionHasSubtraction .

所以我得到了基本的计划。但我要回答如何正确地做到这一点。这可能与您的作业不符,但老实说,那是您作业的问题,而不是我的!

我们不希望所有基本操作都进行虚拟运行时分派(dispatch)和动态分配。我们想要静态多态,而不是动态多态。

幸运的是,在 C++ 中,我们有静态多态性。实现它的典型方法是通过 CRTP——奇怪的重复模板模式。

我们不必在这里使用 CRTP。相反,我们可以依靠 Koenig 查找!

Koenig 查找是在确定什么时operator+ 的事实调用你的父类 friend s 被考虑。我们注入(inject)一个 friend operator+通过使其成为 template 来匹配派生类型内has_addition .

当我们有了 matrix:has_addition ,然后我们调用 + .找到了这个模板。然后我们替换参数的类型——完整类型,而不是 has_addition父类型。

在这个完整的类型中,我们有一个 .add方法。

所以我们可以从这样的类型继承 operator+根据我们从中派生的类型,该类型具有不同的实现,但是这种调度是在编译时静态完成的。

在运行时,has_addition基本消失。相反,我们只是得到一堆 +的路由到 .add .

所以,事不宜迟,这里是 has_addition :

struct has_addition {
// implement + in terms of += on the lhs:
template<class L, class R>
friend std::decay_t<L> operator+( L&& lhs, R&& rhs ) {
if (!std::is_reference<L>{}) { // rvalue lhs
return std::forward<L>(lhs) += rhs;
} else if (!std::is_reference<R>{}) { // rvalue rhs
return std::forward<R>(rhs) += lhs; // assumes + commutes
} else { // rvalue neither
auto tmp = std::forward<L>(lhs);
return tmp += rhs;
}
}
// notice += on an rvalue returns a copy.
// This permits reference lifetime extension:
template<class L, class R>
friend L operator+=( L&& lhs, R&& rhs ) {
lhs.add( std::forward<R>(rhs) );
return std::forward<L>(lhs);
}
};

您通过以下方式使用它:
struct bob : has_addition {
int x = 0;
void add( bob const& rhs ) {
x += rhs.x;
}
};

Live example .

现在都 ++=根据您的 add 为您实现方法。更重要的是,它们有多个右值和左值重载。如果您实现移动构造,您将获得自动性能提升。如果您实现在右侧接受右值的 add,您将获得自动性能提升。

如果你写的右值重载失败 add和移动构造,事情仍然有效。我们将这些因素(添加您可以丢弃的东西,回收您的存储,以及 + 的工作方式)相互分离。结果是更容易编写内置大量微优化的代码。

现在大部分微优化在 has_addition::operator+不需要第一次通过。
struct has_addition {
// implement + in terms of += on the lhs:
template<class L, class R>
friend L operator+( L lhs, R&& rhs ) {
return std::move(lhs) += std::forward<R>(rhs);
}
template<class L, class R>
friend L operator+=( L&& lhs, R&& rhs ) {
lhs.add( std::forward<R>(rhs) );
return std::forward<L>(lhs);
}
};

这更干净,几乎是最佳的。

然后我们将其扩展为
struct has_subtraction; // implement
struct has_binops:
has_subtraction,
has_addition
{};

struct has_operations:
has_binops
{};

但实际上,很少有类型具有所有类型的操作,所以我个人不会喜欢这个。

您可以使用 SFINAE(替换失败不是错误)来检测 add , subtact , multiply , divide , order , equals等在您的类型中实现,并写入 maybe_has_addition<D>D 上进行 SFINAE 测试确定它是否有 D.add( D const& )实现的。当且仅当 has_addition继承自 maybe_has_addition<D> .

然后你可以设置它,以便通过执行以下操作编写大量的运算符重载:
struct matrix: maybe_has_operations<matrix>

当您在 matrix 上实现新操作时,越来越多的重载运算符开始使用。

然而,这是一个不同的问题。

用动态多态(虚拟函数)来做这件事是一团糟。真的,当您编写 matrix1 = matrix2 + matrix3 时,您是否想跳过多个 vtable、动态分配并失去所有编译时类型安全性? ?这不是Java。

friend 位很容易。注意如何 has_addition电话 D.add(D const&) .我们可以制作 add私有(private)内 D ,但前提是我们 friend struct has_addition;体内 D .

所以 has_addition都是 D 的父级和 D的 friend .

我自己,我刚走 add暴露,因为它是无害的。

这种技术有缺点,比如当你添加两个不同的类时会发生什么,这两个类 has_addition .

您可以在 boost.operators 中看到更充实的版本。 ,它也使用相关技术。

关于c++ - 多重继承。这个实现 `+=` 的继承模型背后的想法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40550413/

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