C++ 赋值运算符重载
就像其他运算符一样,您可以重载赋值运算符( = ),用于创建一个对象,比如拷贝构造函数。
下面的实例演示了如何重载赋值运算符。
实例
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
void operator=(const Distance &D )
{
feet = D.feet;
inches = D.inches;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main()
{
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// 使用赋值运算符
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
First Distance : F: 11 I:10 Second Distance :F: 5 I:11 First Distance :F: 5 I:11
C++ 重载运算符和重载函数
Edward_Kenway
MK1***@outlook.com
当用用户自定义类型变量向内置类型变量赋值时,可以使用自定义类型的隐式转换。
#include<iostream> using namespace std; class Int{ private: int n; public: Int(int i); operator int() // 这里就是隐式转换声明,应注意到它与运算符重载的不同之处 { return n; } } int main() { Int a(5); int c=a; // 隐式调用转换函数 cout<<c<<endl; cout<<a<<endl; // 由于未重载Int的<<操作符,将隐式调用转换函数 }上述代码的输出将为:
注意谨慎使用隐式转换函数,因为当你在不需要使用转换函数时,这些函数缺可能会被调用运行;这些不正确的程序会做出一些意想不到的事情,而你又很难判断出原因。
Edward_Kenway
MK1***@outlook.com
舵主
hai***haiduo@outlook.com
楼上代码有问题,但原理没问题。改善如下:
#include<iostream> using namespace std; class Int { private: int n; public: Int(int i) :n(i) {}; operator int() // 这里就是隐式转换声明,应注意到它与运算符重载的不同之处 { return n; } }; int main() { Int a(5); int c = a; // 隐式调用转换函数 cout << c << endl; cout << a << endl; // 由于未重载Int的<<操作符,将隐式调用转换函数 return 0; }舵主
hai***haiduo@outlook.com
焦糖
656***425@qq.com
#include<iostream> using namespace std; class Deam { public: int a; int b; explicit Deam(int i = 10,int j=10) :a(i),b(j) {} void operator-() { a = -a; } void operator--() { a--; } void operator--(int) { a--; } operator int() { return a; } }; int main() { Deam d(5,6); Deam D = d; cout << D.a<<ends<<D.b << endl; }结果:
通过上述代码我们可以发现函数声明转换并没有隐式调用转换函数,而是直接浅拷贝,而浅拷贝存在指针悬空的问题,所以一般禁止隐式转换,在构造函数前加 explicit 关键字,所以其实隐式转换声明的意义不大,实际中直接浅拷贝,不会调用它。
焦糖
656***425@qq.com
艾孜尔江
bju***ft@sina.com
在上述教程中,复合赋值运算符重载没有被提到,但这往往也是经常需要用到的,而且对于新人来讲比较容易出错,我来补充一下吧。
复合赋值操作符是指 += , *= , -= 这一类由基本算数运算符( + 、 - 、 * 、 / )或位运算符(| 、 & 、~等)加 = 号构成的运算符。它们把左右操作数进行相应运算后的结果赋值给左操作符。例如:a += b; 意味着 a = a + b; 复合赋值操作符的返回值,默认是左值。比如a += b;中的a。
在进行复合赋值操作符重载定义的时候,需要注意,其返回值,应该为( * this)<类成员>或者第一个也就是左操作数<非成员函数>。例如:(假设已经自定义算数或位操作运算符)
className & className::operator +=(className & right) { return (*this) = (*this) + right; } className& operator +=(className& left, className& right) { return left = left + right; }className A = a,B = b;(A,B是对象名,a,b是值)。
A += B; (此时A = a + b,整个表达式返回值是a + b)。
重写复合赋值操作符的时候,一定要记得,要把运算结果赋给左值,再返回左值。如果直接返回结果,我们将不会被调用处看到左值被运算的效果。错误代码:(假设已经自定义算数或位操作运算符)
struct Colour { Colour() = default; Colour(const float red, const float green, const float blue) :r(red), g(green), b(blue) {} Colour(const Colour& right) { this->r = right.r; this->g = right.g; this->b = right.b; } bool operator ==(const Colour& right) { if (this->r - right.r <= EPSILON && this->g - right.g <= EPSILON && this->b - right.b <= EPSILON) { return true; } else { return false; } } Colour& operator =(const Colour& right) { if (this == &right) { return *this; } this->r = right.r; this->g = right.g; this->b = right.b; return *this; } Colour ClampColor(Colour& color) { Clamp(color.r, 0.f, 1.f); Clamp(color.g, 0.f, 1.f); Clamp(color.b, 0.f, 1.f); return color; } Colour operator /(const float right) { Colour result; result.r = this->r / right; result.g = this->g / right; result.b = this->b / right; return result; } Colour operator *(const Colour& right) const { Colour result; result.r = this->r * right.r; result.g = this->g * right.g; result.b = this->b * right.b; return result; } Colour operator *(const float& right) const { Colour result; result.r = this->r * right; result.g = this->g * right; result.b = this->b * right; return result; } Colour operator +(const Colour& right) { Colour result; result.r = this->r + right.r; result.g = this->g + right.g; result.b = this->b + right.b; return result; } Colour operator *=(const Colour& right) { return (*this) = (*this * right); } float r, g, b; }; inline std::ostream& operator <<(std::ostream& os, const Colour& right) { os << "r: " << right.r << "; g: " << right.g << "; b: " << right.b; return os; }艾孜尔江
bju***ft@sina.com
上帝也代码
717***589@qq.com
对楼上的代码进行进一步注释说明:
#include <iostream> using namespace std; class Deam { public: int a; int b; //explicit Deam(int i = 10, int j = 10) :a(i), b(j) {} //使用explicit将不会进行隐式转换函数 Deam(int i = 10, int j = 10) :a(i), b(j) { cout << "调用了构造函数" << endl; } explicit Deam(const Deam& deam) { //使用explicit将不会调用拷贝构造函数 cout << "调用了直接拷贝函数" << endl; } void operator-() { a = -a; } void operator--() { a--; } void operator--(int) { a--; } operator int() { //如果拷贝构造函数前使用了explicit修饰则将调用隐式转换函数,拷贝构造函数不会被调用 拷贝构造函数的浅拷贝调用有使指针在析构中悬空风险的问题 return a; } }; int main() { Deam d(5, 6); Deam D = d; //隐式转换函数调用完毕后D将会调用构造函数Deam(int i = 10, int j = 10){} //如果构造函数explicit Deam(int i = 10, int j = 10) :a(i), b(j){}和拷贝构造函数 explicit Deam(const Deam& deam){}将会编译错误,提示类Deam中没有拷贝构造函数 cout << D.a << ends << D.b << endl; }实际输出结果:
上帝也代码
717***589@qq.com