使用 C++ 定义接口(在不丢失基类的所有重载运算符的情况下派生)
Posted
技术标签:
【中文标题】使用 C++ 定义接口(在不丢失基类的所有重载运算符的情况下派生)【英文标题】:Interface definition with C++ (deriving without losing all the overloaded operators from base) 【发布时间】:2015-09-22 13:13:17 【问题描述】:我想用 Eigen 库替换库的一部分。 因为有很多依赖,我想写一个基于 Eigen 的接口。
下面的这个接口使用 cxx11 typedefs 和重载来为 3D 矢量重新创建旧的类接口。这种方法的问题在于,我似乎必须重新实现 Eigen 中已经存在的所有运算符函数/构造函数(+/-/*/..)。
下面的例子说明了这个问题。如果我将 Eigen 的重载运算符与派生类一起使用,则会出现编译器错误。基类按预期工作正常。有没有办法以更少的努力将所需的接口函数/成员添加到 Eigen 类?例如。通过自动将派生类转换为基类?我完全不想重新实现所有 Eigen 函数:D
#include <iostream>
using namespace std;
#include <eigen3/Eigen/Core>
#include <eigen3/Eigen/Dense>
namespace InterfDef
template <class T>
using Vector3 = Eigen::Matrix<T, 3, 1>;
;
namespace InterfImp
template <class T>
class Vector3 : public InterfDef::Vector3<T>
public:
// This is all what I wanted to add :)
T &x = (*this)[0];
T &y = (*this)[1];
T &z = (*this)[2];
// All this crap below, I don't want to implement :(
Vector3(InterfDef::Vector3<T> v) :
InterfDef::Vector3<T>(v)
Vector3(T x, T y, T z) :
InterfDef::Vector3<T>(x,y,z)
Vector3& operator=(const InterfDef::Vector3<T>& v)
(*this)[0] = v[0];
(*this)[1] = v[2];
(*this)[2] = v[2];
return *this;
;
;
问题来了。调用标量乘法运算符仅适用于非派生类,因为向量类的转换在派生后失败。
int main()
InterfDef::Vector3<float> a(1,2,3);
InterfImp::Vector3<float> b(2,3,4);
InterfImp::Vector3<float> c(a);
InterfImp::Vector3<float> d = b;
cout << "Hello World!" << c.x << "; " << c.y << "; " << c.z << std::endl;
cout << "Hello World!" << d.x << "; " << d.y << "; " << d.z << std::endl;
InterfImp::Vector3<float> e = 2 * d; // error with my derived class
InterfDef::Vector3<float> e = 2 * d; // works
cout << "Hello World!" << e[0] << "; " << e[1] << "; " << e[2] << std::endl;
return 0;
【问题讨论】:
【参考方案1】:第一件事
您的外壳使用矩阵 x()、y()、z() 函数。如果矩阵不是 const,它们会返回对其标量的 reference,这会使您的代码如下所示:
Vector3d a;
a.x() = 1;// Ok, a.x() is l-value
a.y() = 2;// ""
a.y() = 3;// ""
注意这是无效的,因为矩阵是常数:
const Vector3d b;
b.x() = 1;// Error! b.x() is r-value
还有其他需要...
Eigen 在Customizing/Extending Eigen page 中准确地记录了您想要做什么,甚至您尝试这样做的方式。
我将只是重复那里所说的话:
第一个解决方案 - 转换构造函数
你总是可以使用带有模板的转换构造函数:
InterfImp
template <class T>
class Vector3 : public InterfDef::Vector3<T>
//...
// This constructor allows you to construct Vector3 from Eigen expressions
template<typename OtherDerived>
Vector3(const Eigen::MatrixBase<OtherDerived>& other)
: InterfDef::Vector3::Vector3d(other)
// This method allows you to assign Eigen expressions to Vector3
template<typename OtherDerived>
Vector3& operator= (const Eigen::MatrixBase <OtherDerived>& other)
this->Base::operator=(other);
return *this;
;
这样,即使知道某些函数返回矩阵表达式(MatrixBase),你也可以转换它们。
注意你应该如何实现 operator=。
第二种解决方案 - Eigen 插件宏
Eigen 允许您自定义它的类,因为它是一个只有头文件的库。 在包含 Eigen 之前,将 EIGEN_MATRIXBASE_PLUGIN 定义为要注入 MarixBase 类的标头:
#define EIGEN_MATRIXBASE_PLUGIN my_matrixbase_injection.h
// Now safely include Eigen headers
在 my_matrixbase_injection.h 中:
// Add what you want to add here.
void superCoolFunc() const
std::cout << "Super COOL!!!\n";
【讨论】:
以上是关于使用 C++ 定义接口(在不丢失基类的所有重载运算符的情况下派生)的主要内容,如果未能解决你的问题,请参考以下文章