模板和操作符重载
Template and operator overloading
我正在检查代码…我发现了一个模板类,它的声明如下所示。
template <class T>
class tType
{
public:
T value;
T operator=(T val){ value = val; return value; }
tType<T> operator=(tType<T> &val){ value = val.value; return *this; }
operator T(){ return value; }
};
我还发现操作符重载,如下…
* * * * * * 1 * * * * * *
template <class T>
bool operator==(T& val, tType<T>& tval) { return(val == tval.value); }
我不明白上面的操作符何时被调用…因为当我…
int main(void)
{
tType<int> x;
x = 5;
if (5 == x)
{
cout << "Both are equal" << endl;
}
return 0;
}
上面说的操作符没有被调用…我还在工作……我还编写了下面的代码用于测试,下面的代码片段被称为…
template<class T>
bool operator==(int x, tType<T>& val) { return (x == val.value); }
我不知道谁叫 1 * * * * * * * * * *
正确的是,您的operator==
没有被调用的原因是缺少const
标识符。在这种情况下,文字5
不能作为参数T& val
的变量引用传递。但是,这并不是故事的全部。
正如你所指出的,即使函数没有被调用,代码仍然会编译和运行。
你的代码仍然工作的原因是由于转换操作符: operator T(){ return value; }
。
转换操作符允许从一种类型隐式强制转换为另一种类型。例如:
struct Number {
Number(int x) : value(x) { }
operator int() { return value; }
private:
int value;
};
int main() {
Number n(5);
int x = n; // 5 -- operator int() at work
int y = n + x; // 10 -- operator int() at work
Number z = x + y; // 15 -- Number(int) at work
cout << x <<" "<< y <<" "<< z << endl;
return 0;
}
这里,operator int()
允许n
转换成int
赋值给x
,再转换成int
与x
相加(结果int
再赋值给y
),而一元构造函数Number(int)
允许x + y
的结果转换回Number
。
在您的代码中,5 == x
仍然可以编译,因为tType<int>
x
通过其operator int()
成员函数转换为int
,然后将结果int
与文字5
进行比较。
然而,对于一个类来说,这可能不是一个很好的设计。例如,为了比较两个
tType<T>
,需要将其中一个转换为T
。
template <class T>
bool operator==(const T& val, const tType<T>& tval) {
cout << "operator==(const T& val, const tType<T>& tval) was called." << endl;
return(val == tval.value);
}
//...
cout << ( tType<int>() == tType<int>() ) << endl; // calls operator==(const T&, const tType<T>&)
你宁愿用一个operator==
代替两个tType<T>
。
另一个更大的问题是不是对称的:
cout << (x1 == 5) << endl; // calls operator==(int,int) (the built-in function)
呵!
要解决所有这些问题,有一个非常简单的设计解决方案。这是摘自Scott Meyers的书Effective C++ Third Edition
(一本非凡的书)。
不是用转换操作符转换回T
,类应该包含一个隐式的一元构造函数来将T
转换为tType<T>
,并且应该为tType<T>
声明一个operator==
:
template <class T>
class tType
{
public:
tType<T>(const T &val) : value(val) { } // unary non-explicit constructor
tType<T> operator=(const tType<T> &val){ value = val.value; return *this; } // only need one
T val() { return value; }
private:
T value; // Note also value is private (encapsulation)
};
template<class T>
bool operator==(const tType<T>& a, const tType<T>& b) { return ( a.val() == b.val() ); }
重要的变化:
- 添加了一个只接受一个值的构造函数;这允许将
T
s转换为tType
s。 - 删除了使用
T
s的赋值运算符(因为现在我们可以将它们转换为tType
s)。 - 只有一个相等运算符,需要两个
const tType<T>&
s,这意味着operator==
可以处理T
s和tType<T>
s的任何组合(或者,更好的是,任何可转换为其中任何一个的东西)。
==
操作符试图将非const
引用绑定到参数-像"5"这样的值不允许这样做…参数应为const
:
template <class T>
bool operator==(const T& val, const tType<T>& tval) { return val == tval.value; }
由于这仍然只支持5 == my_tType
而不支持my_tType == 5
,您可能还需要提供…
template <class T>
bool operator==(const tType<T>& tval, const T& val) { return val == tval.value; }
…对于my_tType1 == my_tType2
…
template <class T>
bool operator==(const tType<T>& tval1, const tType<T>& tval2) {
return tval1.value == tval2.value; }
这使您可以最大限度地控制比较。另一种方法是允许从T
参数隐式构造tType
,但是隐式构造和转换操作符现在通常不被鼓励——它们可能导致歧义和意外创建难以调试的临时对象。另一个问题的主题....
当你说"上面说的操作符没有被调用…实际上发生的是,tType::operator T()
(返回value;
)被隐式调用,返回一个int
,可以作为int
与5
进行比较。因此,您进行了比较,但没有使用自定义operator==
。这是为函数调用找到"最佳匹配"的正常结果。
修改函数
template <class T>
bool operator==(T& val, tType<T>& tval) { return(val == tval.value); }
template <class T>
bool operator==(T const& val, tType<T> const& tval) { return(val == tval.value); }
或
template <class T>
bool operator==(T val, tType<T> tval) { return(val == tval.value); }
您的函数没有被调用,因为5
不能转换为int&
。
- 重载操作符+:表达式必须是整型或无作用域枚举类型
- 重载操作符
- 如何重载操作符==外模板类使用友元函数
- 重载*操作符,使其在左右两边都工作
- 重载操作符<对于非随机迭代器
- 在c++中重载操作符的时间和原因
- 如何在c++中重载=操作符来通过引用进行复制
- 如何在c++中获取定义为友元的重载操作符的地址
- 使用重载操作符的文件操作表达式没有给出预期的结果
- 重载操作符()
- 重载操作符()并在类内使用
- 类中的重载操作符+
- 定时使用重载操作符
- c++带类的重载操作符
- 用列表容器重载[]操作符
- 重载操作符=
- 任何重载操作符()的静态检测
- 重载操作符以处理类对象
- 在使用另一个类的类中重载操作符==
- 派生类和基类中的重载操作符不同