对C++多重继承感到困惑
Confused on C++ multiple inheritance
我对 C++ 的更高级功能有些陌生。昨天,我发布了以下问题,了解了虚拟继承和可怕的死亡钻石。
我还通过其他链接了解到,多重继承通常是错误代码设计的标志,并且通常可以在不使用 MI 的情况下更好地实现相同的结果。问题是...我不知道对于以下问题什么是更好的单继承方法。
我想为两种类型的数字点定义一个接口。输入数字点和输出数字点。界面要简洁,只有访问信息所需的内容。当然,绝大多数属性对于这两种类型的数字点都是通用的。所以对我来说,这是一个明显的继承案例,而不是组合。
我的接口定义看起来像这样:
// Interface Definitions
class IDigitalPoint
{
public:
virtual void CommonDigitalMethod1() = 0;
};
class IDigitalInputPoint : virtual IDigitalPoint
{
public:
virtual void DigitialInputMethod1() = 0;
};
class IDigitalOutputPoint : virtual IDigitalPoint
{
public:
virtual void DigitialOutputMethod1() = 0;
};
我的实现是这样的:
// Implementation of IDigitalPoint
class DigitalPoint : virtual public IDigitalPoint
{
public:
void CommonDigitalMethod1();
void ExtraCommonDigitalMethod2();
}
// Implementation of IDigitalInputPoint
class DigitalInputPoint : public DigitalPoint, public IDigitalInputPoint
{
public:
void DigitialInputMethod1();
void ExtraDigitialInputMethod2();
}
// Implementation of IDigitalOutputPoint
class DigitalOutputPoint : public DigitalPoint, public IDigitalOutputPoint
{
public:
void DigitialOutputMethod1();
void ExtraDigitialOutputMethod2();
}
那么我怎样才能重新格式化这个结构,以避免 MI?
这正是标准库在std::basic_iostream
层次结构中使用虚拟继承的情况。
因此,真正有意义的情况可能很少见。
但是,这完全取决于您为清楚起见而删除的细节,因此无法确定是否存在更好的解决方案。
例如,为什么输入点与输出点不同? DigitalPoint
听起来像是具有属性的 事物 ,可能由 class 建模。但是,DigitalInputPoint
听起来就像是……DigitalPoint
以某种方式耦合到输入源。它有不同的属性吗?不同的行为?它们是什么,为什么?
你可以到下面link了解更多关于多重继承
Avoid Multiple Inheritance
另外,在你的情况下,多重继承是有道理的!!
如果你愿意,你可以使用组合。
"multiple inheritance is typically a sign of a bad code design" - 纯接口的父代不计入此规则。你的 I*
类 是纯接口(只包含纯虚函数)所以你 Digital*Point
类 在这方面没问题
考虑一种不同的方法:
class DigitalPoint
{
public:
void CommonDigitalMethod1();
void ExtraCommonDigitalMethod2();
}
// Implementation of IDigitalInputPoint
class DigitalInputPoint
{
public:
void CommonDigitalMethod1();
void DigitialInputMethod1();
void ExtraDigitialInputMethod2();
}
// Implementation of IDigitalOutputPoint
class DigitalOutputPoint
{
public:
void CommonDigitalMethod1();
void DigitialOutputMethod1();
void ExtraDigitialOutputMethod2();
}
这样使用:
template <class T>
void do_input_stuff(T &digitalInputPoint){
digitalInputPoint.DigitialInputMethod1();
}
您可以通过更清晰的设计和更少的耦合更轻松地实现,并且很可能获得更好的性能。 唯一的缺点是接口是由用法隐式定义的。这可以通过记录模板期望的内容来缓解,最终您将能够在概念中做到这一点,让编译器为您检查它。
另一个缺点是您不能再使用 vector<IDigitalPoint*>
。
您确定需要 3 个接口吗?
class IDigitalPoint
{
public:
virtual void CommonDigitalMethod1() = 0;
};
enum class Direction : bool { Input, Output };
template <Direction direction>
class DigitalPoint : public IDigitalPoint
{
public:
void CommonDigitalMethod1() {}
void ExtraCommonDigitalMethod2() {}
virtual void DigitialMethod1() = 0;
};
class DigitalInputPoint : public DigitalPoint<Direction::Input>
{
public:
void DigitialInputMethod1() {}
void ExtraDigitialInputMethod2() {}
// This is like DigitialInputMethod1()
virtual void DigitialMethod1() override
{}
};
class DigitalOutputPoint : public DigitalPoint<Direction::Output>
{
public:
void DigitialOutputMethod1() {}
void ExtraDigitialOutputMethod2() {}
// This is like DigitialOutputMethod1()
virtual void DigitialMethod1() override
{}
};
(Multiple) 继承和接口往往会使简单关系不必要地复杂化。
这里只需要一个简单的结构和几个独立的功能:
namespace example {
struct Point { T x; T y; }
Point read_method();
void write_method(const Point&)
void common_method(Point&);
void extra_common_method(Point&);
} // example
common_method
可能是Point的成员函数的候选。
不太常见的 extra_common_method
可能是另一个 class 封装 Point
.
的候选者
您可以使用组合而不是继承。 Live Example
如果 child 类 不使用 DigitalPoint 的功能,那么您可以尝试使用 CRTP。如果您不了解 CRTP,可能会感到困惑,但当它适合时,它就像一个魅力。 Live Example
我对 C++ 的更高级功能有些陌生。昨天,我发布了以下问题,了解了虚拟继承和可怕的死亡钻石。
我还通过其他链接了解到,多重继承通常是错误代码设计的标志,并且通常可以在不使用 MI 的情况下更好地实现相同的结果。问题是...我不知道对于以下问题什么是更好的单继承方法。
我想为两种类型的数字点定义一个接口。输入数字点和输出数字点。界面要简洁,只有访问信息所需的内容。当然,绝大多数属性对于这两种类型的数字点都是通用的。所以对我来说,这是一个明显的继承案例,而不是组合。
我的接口定义看起来像这样:
// Interface Definitions
class IDigitalPoint
{
public:
virtual void CommonDigitalMethod1() = 0;
};
class IDigitalInputPoint : virtual IDigitalPoint
{
public:
virtual void DigitialInputMethod1() = 0;
};
class IDigitalOutputPoint : virtual IDigitalPoint
{
public:
virtual void DigitialOutputMethod1() = 0;
};
我的实现是这样的:
// Implementation of IDigitalPoint
class DigitalPoint : virtual public IDigitalPoint
{
public:
void CommonDigitalMethod1();
void ExtraCommonDigitalMethod2();
}
// Implementation of IDigitalInputPoint
class DigitalInputPoint : public DigitalPoint, public IDigitalInputPoint
{
public:
void DigitialInputMethod1();
void ExtraDigitialInputMethod2();
}
// Implementation of IDigitalOutputPoint
class DigitalOutputPoint : public DigitalPoint, public IDigitalOutputPoint
{
public:
void DigitialOutputMethod1();
void ExtraDigitialOutputMethod2();
}
那么我怎样才能重新格式化这个结构,以避免 MI?
这正是标准库在std::basic_iostream
层次结构中使用虚拟继承的情况。
因此,真正有意义的情况可能很少见。
但是,这完全取决于您为清楚起见而删除的细节,因此无法确定是否存在更好的解决方案。
例如,为什么输入点与输出点不同? DigitalPoint
听起来像是具有属性的 事物 ,可能由 class 建模。但是,DigitalInputPoint
听起来就像是……DigitalPoint
以某种方式耦合到输入源。它有不同的属性吗?不同的行为?它们是什么,为什么?
你可以到下面link了解更多关于多重继承 Avoid Multiple Inheritance
另外,在你的情况下,多重继承是有道理的!! 如果你愿意,你可以使用组合。
"multiple inheritance is typically a sign of a bad code design" - 纯接口的父代不计入此规则。你的 I*
类 是纯接口(只包含纯虚函数)所以你 Digital*Point
类 在这方面没问题
考虑一种不同的方法:
class DigitalPoint
{
public:
void CommonDigitalMethod1();
void ExtraCommonDigitalMethod2();
}
// Implementation of IDigitalInputPoint
class DigitalInputPoint
{
public:
void CommonDigitalMethod1();
void DigitialInputMethod1();
void ExtraDigitialInputMethod2();
}
// Implementation of IDigitalOutputPoint
class DigitalOutputPoint
{
public:
void CommonDigitalMethod1();
void DigitialOutputMethod1();
void ExtraDigitialOutputMethod2();
}
这样使用:
template <class T>
void do_input_stuff(T &digitalInputPoint){
digitalInputPoint.DigitialInputMethod1();
}
您可以通过更清晰的设计和更少的耦合更轻松地实现,并且很可能获得更好的性能。 唯一的缺点是接口是由用法隐式定义的。这可以通过记录模板期望的内容来缓解,最终您将能够在概念中做到这一点,让编译器为您检查它。
另一个缺点是您不能再使用 vector<IDigitalPoint*>
。
您确定需要 3 个接口吗?
class IDigitalPoint
{
public:
virtual void CommonDigitalMethod1() = 0;
};
enum class Direction : bool { Input, Output };
template <Direction direction>
class DigitalPoint : public IDigitalPoint
{
public:
void CommonDigitalMethod1() {}
void ExtraCommonDigitalMethod2() {}
virtual void DigitialMethod1() = 0;
};
class DigitalInputPoint : public DigitalPoint<Direction::Input>
{
public:
void DigitialInputMethod1() {}
void ExtraDigitialInputMethod2() {}
// This is like DigitialInputMethod1()
virtual void DigitialMethod1() override
{}
};
class DigitalOutputPoint : public DigitalPoint<Direction::Output>
{
public:
void DigitialOutputMethod1() {}
void ExtraDigitialOutputMethod2() {}
// This is like DigitialOutputMethod1()
virtual void DigitialMethod1() override
{}
};
(Multiple) 继承和接口往往会使简单关系不必要地复杂化。
这里只需要一个简单的结构和几个独立的功能:
namespace example {
struct Point { T x; T y; }
Point read_method();
void write_method(const Point&)
void common_method(Point&);
void extra_common_method(Point&);
} // example
common_method
可能是Point的成员函数的候选。
不太常见的 extra_common_method
可能是另一个 class 封装 Point
.
您可以使用组合而不是继承。 Live Example
如果 child 类 不使用 DigitalPoint 的功能,那么您可以尝试使用 CRTP。如果您不了解 CRTP,可能会感到困惑,但当它适合时,它就像一个魅力。 Live Example