微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C ++基类构造函数,将派生类作为参数?

如何解决C ++基类构造函数,将派生类作为参数?

用例:

  • Vector 类(实现一些数学运算)和派生的 Vector2D
  • 理想情况下,两个类都应允许彼此“复制构造”

Vector

namespace mu {
template<std::size_t N,typename T>
class Vector {
  public:
  // ...

  template <typename... TArgs>
  Vector(TArgs... args) : data({args...}) {}

  Vector(const Vector &other) = default; // copy constructor

  // ...
  protected:
    std::array<T,N> data;
};
}

Vector2D

namespace mu {
template<typename T>
class Vector2D : public Vector<2,T> {

  public:

  using Vector<2,T>::Vector; // inherit base class constructors

  Vector2D(const Vector<2,T>& other) : Vector<2,T>(other) {}

  // Vector2D specific functions,e.g. rotation
  //...

};
}

注意:实际的类包含更多内容,但我将其简化为我认为在这里最重要的代码

问题是我无法实现一种可以从Vector构造Vector2D的方式,请参见下面的代码。所有其他情况都可以正常工作。

// Example 1 (compiles)
mu::Vector<2,int> a{1,2};
mu::Vector<2,int> b{a};

// Example 2 (compiles)
mu::Vector2D<int> c{1,2};
mu::Vector2D<int> d{c};

// Example 3 (compiles)
mu::Vector<2,int> e{1,2};
mu::Vector2D<int> f{e};

// Example 4 (doesn't compile)  <-- how to get this to work?
mu::Vector2D<int> g{1,int> h{g};

当然,更普遍的问题是继承是否是构造这些类的正确方法。但是我希望Vector2D具有Vector的所有功能以及Vector没有的其他功能

解决方法

您的Vector类具有两个构造函数:一个模板(用于值)和默认的复制构造函数。

问题:首选复制构造函数,但前提是完全匹配。

因此,用b初始化a

mu::Vector<2,int> a{1,2};
mu::Vector<2,int> b{a};

首选复制构造函数,因为a是完全匹配

但是,用h初始化g

mu::Vector2D<int> g{1,int> h{g};

g可以转换为mu::Vector<2,int>,但不是完全匹配,因此首选使用模板构造函数,但不兼容。

一种可能的解决方案:只有一个自变量且该自变量是从mu::Vector派生时,SFINAE禁用模板构造器。

例如

template <typename... TArgs,typename std::enable_if_t<sizeof...(TArgs) == N
                                or (not std::is_base_of_v<Vector,TArgs> && ...),int> = 0>
Vector(TArgs const & ... args) : data({args...}) {}
,

不考虑继承是否适合此特定任务,失败的直接原因是全部使用template <typename... TArgs>的构造函数。它将拦截不是副本的所有构造,并且派生类对象的构造不是。这是因为从派生到基数的转换是一次转换,并且模板构造函数不需要转换,因此是更好的匹配。

如果参数适合于构造std::array成员,则希望限制包罗万象的构造函数仅包括在重载解析中。这是SFINAE的标准应用程序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。