模板化一个类,然后重载运算符 (C++)
Posted
技术标签:
【中文标题】模板化一个类,然后重载运算符 (C++)【英文标题】:Templating a class and then overloading operators (C++) 【发布时间】:2014-11-17 11:22:09 【问题描述】:下面的代码不起作用,我找不到原因,非常感谢任何帮助。
//In Maths.h file
template <class T> class Maths
public:
Maths<T>(T lhs);
template<typename U>
Maths<T>(const Maths<U>& otherMaths);
~Maths();
template <typename U>
Maths<T>& operator+(const Maths<U>& rhs);
template <typename U>
Maths<T>& operator*(const Maths<U>& rhs);
template <typename U>
Maths<T>& operator-(const Maths<U>& rhs);
private:
T _lhs;
;
//In Maths.cpp file
#include "Maths.h"
template <class T>
Maths<T>::Maths(T lhs)
_lhs = lhs;
return _lhs;
template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
_lhs = otherMaths._lhs;
template <class T>
Maths<T>::~Maths()
template <class T> template <typename U>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return Maths._lhs + rhs;
template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<T>& rhs) return Maths._lhs - rhs;
template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<T>& rhs) return Maths._lhs * rhs;
问题在于 VS 无法识别关键字运算符(即不显示为蓝色),这是为什么呢?
编辑:
我已经删除了下面指出的错误。将所有定义移到 .h 文件中,代码仍然无法编译,此处发现错误:http://i.imgur.com/Z9rWOFh.png
新代码(如果有兴趣):
//in Maths.h file
template <class T> class Maths
public:
Maths<T>(T lhs);
template<typename U>
Maths<T>(const Maths<U>& otherMaths);
~Maths();
T& getValue() return _lhs; ;
template <typename U>
Maths<T>& operator+(const Maths<U>& rhs);
template <typename U>
Maths<T>& operator*(const Maths<U>& rhs);
template <typename U>
Maths<T>& operator-(const Maths<U>& rhs);
private:
T _lhs;
;
template <class T>
Maths<T>::Maths(T lhs)
_lhs = lhs;
template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
_lhs = otherMaths.getValue();
template <class T>
Maths<T>::~Maths()
template <class T>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return _lhs + rhs.getValue();
template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<U>& rhs) return _lhs - rhs.getValue();
template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<U>& rhs) return _lhs * rhs.getValue();
//in main.cpp
#include "Maths.h"
int main()
Maths<int> x = 1;
Maths<int> y = 5;
x + y;
return 0;
【问题讨论】:
您不需要在Maths
之后为您的内联成员函数返回类型指定<T>
,也不需要为构造函数名称指定。
请阅读Why can templates only be implemented in the header file? 然后,我建议使用 g++ 或 clang++ 以获得可以理解的错误消息:coliru.stacked-crooked.com/a/9aaa7134ef8a6c28
我建议你阅读this - 你有很多基本错误。
@TonyD 我更担心 VS 不将运算符识别为关键字的原因。这段代码(连同我拥有的 main.cpp)在 g++ 中运行良好,但我在大学课程的要求是代码要在 VS 上运行。您能看到我的代码无法将运算符识别为关键字的任何原因吗? (例如:在上面的代码 sn-p 上它读起来很好,而在 VS 上它看起来像这样i.imgur.com/upahPNx.png)
如果某些东西适用于 g++ 并不意味着它应该适用于另一个编译器。有些行为在标准上是未定义的,有些编译器实现了“预期的”行为,而另一些则没有。我强烈建议您修复 cmets 和 answers 指出的错误,然后看看它是否仍然不起作用。
【参考方案1】:
-
不能在多个文件中分离模板类的声明和实现。因此,您需要将所有实现移动到标题中。
您有很多现在看不到的错误(例如在构造函数中返回)。我建议您在类声明中移动实现。更正它、调试、做一些测试,然后如果您仍然需要它,请尝试将实现移到外面。
Visual Studio(或本例中的 IntelliSense)有时会在突出显示时出现一些错误(或者可能只是速度很慢)。不要专注于此。如果出现问题,编译器会为您提供更准确的错误和警告。
我可以告诉你一些错误:
return
在构造函数中 Maths<T>( T lhs )
;
return Maths._lhs + rhs;
- Maths
是一个类,但您使用实例进行操作。如果您需要获取指向当前实例的指针,请使用this->_lhs
,或者只使用_lhs
;
_lhs = otherMaths._lhs;
- 您无法访问 private
字段;您可以获得Maths< T >
类的值_lhs
,但Maths< U >
是一个不同的类。所以你需要做一些像T& value( ) return _lhs;
这样的函数并在这里使用它;
编辑:
还有一些错误。正如您在错误描述中看到的,您的实现
template <class T>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return _lhs + rhs.getValue();
与函数定义不匹配
// in class template <class T> class Maths
template <typename U>
Maths<T>& operator+(const Maths<U>& rhs);
(就像一个游戏 - 找出不同之处 =D) 正确的做法是这样的:
// declaration
template <typename U>
Maths<T> operator+(const Maths<U>& rhs);
// ...
// definition
template <class T>
template <typename U>
Maths<T> Maths<T>::operator+(const Maths<U>& rhs) return _lhs + rhs.getValue( );
我已从声明中删除 &
并将 template <typename U>
添加到定义中。对于operator-
和operator*
,您需要删除&
。
下一个问题你会发现getValue
没有常量声明。您需要添加新方法。
const T& getValue( ) const return _lhs;
【讨论】:
关于 1.:不,您可以将它们分开。对于泛型编程的非常特殊的情况,比如当你只支持浮动类型时,这甚至是有意义的。这里的关键词是“显式专业化”。 @phresnel 是对的。另一种方法是在类声明之后将.cpp
包含在.h
文件中。我认为这里的问题不是分离。
@NikolayKondratyev:我希望你在.h
中测量.inl
。
我已经更新了主要问题正文中的代码和我的编译器错误
@NikolayKondratyev 抱歉,由于草率,我错过了您在我的编辑答案中提出的大部分观点(我的讲师正在测试某些东西,但在编译失败后我忘记将其改回)删除和引用允许我的代码编译,我只是在写草率和糟糕的代码。我决心在这方面做得更好!非常感谢大家的帮助!【参考方案2】:
哎呀...您还没有采纳早期反馈。下面是一些可编译的代码:
template <class T>
class Maths
public:
Maths(T lhs);
template<typename U>
Maths(const Maths<U>& otherMaths);
~Maths();
T& getValue() return _lhs; ;
const T getValue() const return _lhs; ;
template <typename U>
Maths<T> operator+(const Maths<U>& rhs);
template <typename U>
Maths<T> operator*(const Maths<U>& rhs);
template <typename U>
Maths<T> operator-(const Maths<U>& rhs);
private:
T _lhs;
;
template <class T>
Maths<T>::Maths(T lhs)
_lhs = lhs;
template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
_lhs = otherMaths.getValue();
template <class T>
Maths<T>::~Maths()
template <class T> template <typename U>
Maths<T> Maths<T>::operator+(const Maths<U>& rhs) return _lhs + rhs.getValue();
template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<U>& rhs) return _lhs - rhs.getValue();
template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<U>& rhs) return _lhs * rhs.getValue();
//in main.cpp
#include "Maths.h"
int main()
Maths<int> x = 1;
Maths<int> y = 5;
x + y;
请注意,编译所需的更正包括将const
函数添加到getValue
,将运算符声明更改为按值而不是按引用返回Math<T>
s。
话虽如此,将Math<int>
添加到Math<double>
返回Math<int>
并没有多大意义,因为这在这两种类型中不太精确。下面的代码使用decltype
来选择 C++ 本身在对这两种类型进行操作时使用的相同类型,例如int
乘以 double
返回 double
,将 uint8_t
(又名 unsigned char
)添加到 unsigned int
返回另一个 unsigned int
。我还放弃了n_
的_lhs
成员变量名称,因为_lhs
仅适用于运营商内部的一个相当短视的角度...... rhs
的“_lhs
”正在使用但没有无论如何都有意义...
template <class T>
class Maths
public:
Maths(T n);
template<typename U>
Maths(const Maths<U>& otherMaths);
~Maths();
T& getValue() return n_; ;
const T getValue() const return n_; ;
template <typename U>
Maths<decltype(T()+U())> operator+(const Maths<U>& rhs);
template <typename U>
Maths<decltype(T()*U())> operator*(const Maths<U>& rhs);
template <typename U>
Maths<decltype(T()-U())> operator-(const Maths<U>& rhs);
private:
T n_;
;
template <class T>
Maths<T>::Maths(T n)
n_ = n;
template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
n_ = otherMaths.n_;
template <class T>
Maths<T>::~Maths()
template <class T> template <typename U>
Maths<decltype(T()+U())> Maths<T>::operator+(const Maths<U>& rhs)
return getValue() + rhs.getValue();
template <class T> template <typename U>
Maths<decltype(T()-U())> Maths<T>::operator-(const Maths<U>& rhs)
return getValue() - rhs.getValue();
template <class T> template <typename U>
Maths<decltype(T()*U())> Maths<T>::operator*(const Maths<U>& rhs)
return getValue() * rhs.getValue();
//in main.cpp
#include "Maths.h"
int main()
Maths<int> x = 1;
Maths<int> y = 5;
x + y;
【讨论】:
以上是关于模板化一个类,然后重载运算符 (C++)的主要内容,如果未能解决你的问题,请参考以下文章
重载 [] 和 = 运算符以在 C++ 中接受我的模板类的值