使用构造函数继承来提供兄弟类型之间的转换
Use constructor inheritance to provide conversion between sibling types
我想允许以下行为:
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) 不能与复制构造函数混淆(如果我没记错的话,模板构造函数不被视为复制构造函数,因为非模板复制构造函数优先于模板构造函数,如果它们具有相同的签名作为实例化后的复制构造函数)。
所以,constructor(1)应该在derived中继承class:
// 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 的派生 class,不会因 static_assert
子句而导致错误。
但这并没有发生,因为编译错误表明没有找到从 Signal1
到 Signal2
的转换。
为什么基础构造函数没有被正确继承,派生的 classes 中真正继承的是什么?
注意:在我的真实代码中(为简单起见未在此示例中显示),派生信号是模板,转换运算符仅适用于显式转换(使用 (Type)object
运算符),这使得我在函数之间发送对象的地方的行太长。这就是为什么我想寻找一种通过构造函数来完成它的方法。
注意 2:请关注 C++ 问题(它真的被继承了吗?)而不是其他 OOP 考虑因素(例如,构造派生对象是否有意义来自基本类?),因为这是我的真实代码的一个非常简化的例子。
这可以在没有模板的情况下通过添加第二层基础来完成 类:
class SignalBase
{
/* all the members */
};
struct CopyableSignalBase : SignalBase
{
// not actually a copy constructor, so using will pick it up
CopyableSignalBase(const SignalBase& src) : SignalBase(src) {}
// make all other (not copy and not default) constructors available too
using SignalBase::SignalBase;
// since using doesn't introduce default constructor, provide it
// if and only if SignalBase had one
CopyableSignalBase() = default;
};
struct Signal1 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };
struct Signal2 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };
请注意,根据 this feature matrix,在 VS14 之前,Visual Studio 根本无法处理继承构造函数。但是如果没有构造函数继承,整个问题就毫无意义。
我想允许以下行为:
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) 不能与复制构造函数混淆(如果我没记错的话,模板构造函数不被视为复制构造函数,因为非模板复制构造函数优先于模板构造函数,如果它们具有相同的签名作为实例化后的复制构造函数)。
所以,constructor(1)应该在derived中继承class:
// 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 的派生 class,不会因 static_assert
子句而导致错误。
但这并没有发生,因为编译错误表明没有找到从 Signal1
到 Signal2
的转换。
为什么基础构造函数没有被正确继承,派生的 classes 中真正继承的是什么?
注意:在我的真实代码中(为简单起见未在此示例中显示),派生信号是模板,转换运算符仅适用于显式转换(使用 (Type)object
运算符),这使得我在函数之间发送对象的地方的行太长。这就是为什么我想寻找一种通过构造函数来完成它的方法。
注意 2:请关注 C++ 问题(它真的被继承了吗?)而不是其他 OOP 考虑因素(例如,构造派生对象是否有意义来自基本类?),因为这是我的真实代码的一个非常简化的例子。
这可以在没有模板的情况下通过添加第二层基础来完成 类:
class SignalBase
{
/* all the members */
};
struct CopyableSignalBase : SignalBase
{
// not actually a copy constructor, so using will pick it up
CopyableSignalBase(const SignalBase& src) : SignalBase(src) {}
// make all other (not copy and not default) constructors available too
using SignalBase::SignalBase;
// since using doesn't introduce default constructor, provide it
// if and only if SignalBase had one
CopyableSignalBase() = default;
};
struct Signal1 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };
struct Signal2 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };
请注意,根据 this feature matrix,在 VS14 之前,Visual Studio 根本无法处理继承构造函数。但是如果没有构造函数继承,整个问题就毫无意义。