【发布时间】:2015-05-14 21:57:38
【问题描述】:
我想允许以下行为:
struct SignalBase {};
struct Signal1 : public SignalBase
{ using SignalBase::SignalBase; };
struct Signal2 : public SignalBase
{ using SignalBase::SignalBase; };
int main()
{
Signal1 s1;
Signal2 s2(s1);
}
当然,这是行不通的,因为SignalBase 没有接收派生类型的构造函数,并且复制构造函数不是通过using 子句继承的。
我尝试使用 SignalBase 中的模板构造函数来解决这个问题:
// External function:
template<typename Derived, typename Base>
constexpr bool isDerived()
{
return std::is_base_of<Base, Derived>::value and
!std::is_same<Base, Derived>::value;
}
struct SignalBase
{
template<typename Signal>
SignalBase(Signal const& s) // (1)
{ static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }
};
由于构造函数 (1) 不能与复制构造函数混淆(如果我没记错的话,模板构造函数不被视为复制构造函数,因为非模板复制构造函数如果具有相同的签名,则优先于模板构造函数实例化后的复制构造函数)。
所以,构造函数(1)应该在派生类中继承:
// struct Signal1 inherits:
template<typename Signal>
Signal1(Signal const& s) // (2)
{ static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }
// struct Signal2 inherits:
template<typename Signal>
Signal2(Signal const& s) // (3)
{ static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }
还有这样一行:
Signal2 s2(s1);
应使用Signal = Signal1 实例化 (3),这是 Signal 的派生类,不会因 static_assert 子句而导致错误。
但这不会发生,因为编译错误表明没有找到从 Signal1 到 Signal2 的转换。
为什么基构造函数没有被正确继承,派生类中真正继承了什么?
注意:在我的真实代码中(为简单起见,此示例中未显示),派生信号是模板,并且强制转换运算符仅适用于显式强制转换(使用 (Type)object 运算符),它在我在函数之间发送对象的地方使行太长。这就是为什么我想通过构造函数来寻找一种方法。
注意 2:请关注 C++ 问题(真的被继承了?),而不是其他 OOP 考虑因素(例如,从基类构造派生对象是否有意义?) ,因为这是我真实代码的一个非常简化的示例。
【问题讨论】:
-
Signal1和Signal2将SignalBase作为它们最低的共同祖先。因此,在执行Signal2 s2(s1)时,保留除s1的SignalBase部分之外的任何内容都是没有意义的。转换为SignalBase应该这样做 -
您希望
Signal2 s2(s1)做什么,确切地说?在一个明确的 OOP 类层次结构中,Signal2根据定义对Signal1一无所知。给定它不应该处理的东西的参数,它的构造函数应该如何创建一个有用的实例?这就像从Cat构造Dog,因为两者都是Animals。我想知道继承是否适合这项工作。 -
@Christian Hackl 关键是派生类没有自己的数据成员。我创建它们只是为了消除其他模板和函数模板的歧义,但在某些地方我想重用与不同信号完美配合的函数。
-
@Rerito 看到我在帖子末尾的注释。
-
为什么需要模板?请描述您在使用构造函数时遇到的具体问题,而不是
const SignalBase&。哦,我明白了,你正试图让using工作。
标签: c++ templates c++11 constructor