c++ 11不能强制转换模板继承
C++11 Cannot cast template inheritance
我正在为一个OpenGLES项目编写数学模块。我写了一个类来管理一个通用大小的浮点矩阵
template <unsigned int N>
class MatrixN {
public:
float m[N*N];
MatrixN(){}
virtual ~MatrixN(){}
void identify();
MatrixN& operator=(const MatrixN& b);
};
template <unsigned int N>
MatrixN<N> operator*(const MatrixN<N>& a, const MatrixN<N>& b);
//CPP file implementation
template<unsigned int N>
MatrixN<N> operator*(const MatrixN<N>&a, const MatrixN<N> &b) {
MatrixN<N> matrix;
for(unsigned int i = 0; i < N; i++){
for(unsigned int j = 0; j < N; j++){
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++){
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
然后创建一个子类来管理3x3矩阵
class Matrix3 : public MatrixN<3> {
public:
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
为什么当我执行这个操作
//Rotations instances of Matrix3
Matrix3 rotation = this->rotation * input.rotation;
我得到这个错误在编译时?
no viable conversion from 'MatrixN<3U>' to 'const Matrix3'
这是因为乘法运算返回的是MatrixN<3>
而不是Matrix3
在这种情况下,您可以在Matrix3
中创建一个接受MatrixN<3>
的构造函数
代码(未测试):
class Matrix3 : public MatrixN<3> {
public:
Matrix3 (const MatrixN<3>& mat){/*set internal values*/}
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
问题是operator*
的结果类型是MatrixN<N>
,但rotation
的类型是Matrix3
,并且隐式强制转换不起作用,因为这将是向下强制转换。
作为一种可能的解决方案,您可以为Matrix3
输入和输出覆盖operator*
。如果您想重用helper函数,可以使用它来节省一些代码。例如:
template< MatrixType >
MatrixType multiple(const MatrixType& a, const MatrixType& b, size_t N )
{
MatrixType matrix;
for(unsigned int i = 0; i < N; i++)
{
for(unsigned int j = 0; j < N; j++)
{
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++)
{
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
Matrix3 operator*(const Matrix3& a, const Matrix3& b)
{
return multiple< Matrix3 >( a, b, 3 );
}
请注意,这可能有点危险,因为没有任何防止溢出的保护,所以multiple
函数的"用户"应该小心。
乘法运算符是根据MatrixN<N>
实现的。您的派生类型Matrix3
不是其中之一,而是其中一个作为基础。因此,仍然有派生到基的转换来调用操作符,并且返回的类型不是您想要的类型。
你可以定义你的乘法运算符接受任何类型作为参数并返回该类型,然后约束它只接受从MatrixN<N>
派生的类型:
template<typename Matrix,
typename = std::enable_if_t<std::is_base_of<MatrixN<Matrix::size>, Matrix>::value>>
Matrix operator*(const Matrix&a, const Matrix &b) {
constexpr unsigned N = Matrix::size;
Matrix matrix;
for(unsigned int i = 0; i < N; i++){
for(unsigned int j = 0; j < N; j++){
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++){
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
要静态确定矩阵的大小N
,类模板需要有一个嵌套的常量表达式值size
,例如:
template <unsigned int N>
class MatrixN {
public:
static constexpr unsigned int size = N;
// ...
};
这段代码可以工作。但是你应该知道这是非常非常危险的。
MatrixN<3> tmp_scoped_var = this->rotation * input.rotation;
Matrix3 &rotation = reinterpret_cast<Matrix3 &>(tmp_scoped_var);
rotation.rotateX(1.1); // Call the method of B
因为tmp_scoped_var
保存了MatrixN<N>
的operator *
返回的数据。因此,内存将在超出作用域时被释放。这段代码告诉编译器在MatrixN<N>
变量上强制使用Matrix3
的方法。Matrix3
和MatrixN<N>
的内存布局是相同的,否则可能会导致程序段故障而崩溃。
根据您的代码,您可能希望在模板参数N
等于3
时添加一些特定的方法。所以可以使用类模板特化。
template <>
class MatrixN<3> {
public:
float m[3*3];
MatrixN(){}
virtual ~MatrixN(){}
void identify();
MatrixN& operator=(const MatrixN<3>& b);
public:
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
- 继承模板化转换运算符
- 共享指针继承,而不先显式强制转换
- 事件系统:使用类型转换或联合进行继承
- 从继承的类C++强制转换
- 继承会导致不明确的转换
- 将 void* 强制转换为多个继承类的超类不会调用正确的方法
- C++ 关于类继承的隐式转换
- 使用类继承将单个喜欢的列表转换为双向链表
- 如何将C++继承的带有函数的类转换为C样式?
- C++ MSVC 中的访问冲突,但不在 GCC 中进行多重继承和强制转换
- 模板实例和继承的转换错误
- 为什么 GCC 在使用继承的构造函数时警告我无用的强制转换
- 为什么私有继承对象允许成员函数将派生的*转换为基*,而外部不能
- 在多重继承场景中动态强制转换类型
- 使用模板无法按预期工作进行继承和强制转换
- 将void*强制转换为具有多重继承的类
- 避免在继承的树类中进行下转换
- C++ 中的多重继承转换
- c++错误:继承转换无效
- GCC将私有继承转换为父