运算符重载(二)
● 对称运算符通常定义为非成员函数以支持首个操作数的类型转换
struct Str
{
int val = 0;
Str(int input)
: val(input)
{}
auto operator+(Str x)
{
std::cout << "auto operator+(Str x)\n";
return Str(val + x.val);
}
};
int main()
{
Str x = 3;
Str z = x + 4; //通过类Str的构造函数将4转换为Str类型与x相加
Str u = 4 + x; //Error: Invalid operands to binary expression ('int' and 'Str')
return 0;
}
struct Str
{
int val = 0;
Str(int input)
: val(input)
{}
};
auto operator+(Str input1, Str input2)
{
std::cout << "auto operator+(Str input1, Str input2)\n";
return Str(input1.val + input2.val);
}
int main()
{
Str x = 3;
Str y = x + 3; OK
return 0;
}
struct Str
{
Str(int input)
: val(input)
{}
friend auto operator+(Str, Str);
private:
int val = 0;
};
auto operator+(Str input1, Str input2)
{
std::cout << "auto operator+(Str input1, Str input2)\n";
return Str(input1.val + input2.val);
}
int main()
{
Str x = 3;
Str y = x + 3;
Str z = 3 + y;
return 0;
}
● 移位运算符一定要定义为非成员函数,因为其首个操作数类型为流类型
struct Str
{
Str(int input)
: val(input)
{}
friend auto operator+(Str input1, Str input2)
{
return Str(input1.val + input2.val);
}
friend auto& operator<<(std::ostream& output, Str input) //返回引用,第一个参数类型是std::ostream
{
output << input.val;
return output;
}
private:
int val = 0;
};
int main()
{
Str x = 3;
Str y = x + 3;
std::cout << x << ' ' << y <<std::endl;
return 0;
}
● 赋值运算符也可以接收一般参数
struct Str
{
Str()
: val(0)
{}
Str(int input)
: val(input)
{}
Str& operator=(const Str& input) //重载赋值运算符1。重载运算符只接受一个参数,因为缺省参数是*this。
{
val = input.val;
return *this;
}
Str& operator=(const std::string& input) //重载赋值运算符2
{
val = static_cast<int>(input.size());
return *this;
}
//private:
int val;
};
int main()
{
Str x = 3;
//Str y = "12345"; //调用构造函数而非重载赋值运算符
Str y;
y = "12345"; //调用重载赋值运算符
std::cout << y.val << std::endl;
return 0;
}
● operator [] 通常返回引用
struct Str
{
Str()
: val(0)
{}
Str(int input)
: val(input)
{}
Str& operator=(const Str& input) //重载赋值运算符1,
{
val = input.val;
return *this;
}
Str& operator=(const std::string& input) //重载赋值运算符2
{
val = static_cast<int>(input.size());
return *this;
}
//int operator[](int id) //返回“值”,只读,不可执行写操作
int& operator[](int id) //#1返回引用,可读可写,但是*this可被修改
{
return val;
}
int operator[](int id) const //#2const修饰构成重载返回“值”,可读不可写,即*this不可被修改
{
return val;
}
//private:
int val;
};
int main()
{
Str x = 3;
x = "12345";
std::cout << x[0] << '\n'; //读
x[0] = 100; //写
std::cout << x[0] << '\n';
const Str cx = 3;
//std::cout << cx[0] << std::endl; //见#1,Error: No viable overloaded operator[] for type 'const Str'
std::cout << cx[0] << std::endl; //OK,见#2
return 0;
}
● 自增、自减运算符的前缀、后缀重载方法
struct Str
{
Str()
: val(0)
{}
Str(int input)
: val(input)
{}
//Str operator++() //返回“值”,Error: cannot increment value of type 'void'
Str& operator++() //前缀自增
{
++val;
return *this;
}
Str operator++(int) //后缀自增,返回“值”
{
Str tmp(*this); //调用拷贝构造,构造临时对象,编译器不一定能优化,导致性能上的损失
++val;
return tmp;
}
//private:
int val;
};
int main()
{
Str s;
++(++s); //调用前缀自增
std::cout << s.val <<std::endl;
std::cout << (s++).val << std::endl; //调用后缀自增
std::cout << s.val <<std::endl;
return 0;
}
● 使用解引用运算符( * )与成员访问运算符( -> )模拟指针行为
– 注意“ .” 运算符不能重载
通过类对象而不是指向类对象的指针调用其成员的,所以不能重载
struct Str
{
Str(int* p)
: ptr(p)
{}
//operator*() //Error: C++ requires a type specifier for all declarations
int& operator*() //返回引用,支持读写操作
{
return *ptr;
}
int operator*() const //返回“值”,只读
{
return *ptr;
}
private:
int* ptr;
};
int main()
{
int x = 100;
Str ptr(&x);
std::cout << *ptr << std::endl; //读
*ptr = 101; //写
std::cout << *ptr << std::endl;
return 0;
}
– “→” 会递归调用 操作 “→”
struct Str
{
Str(int* p)
: ptr(p)
{}
Str* operator ->() //重载运算符本质上是个函数
{
return this;
}
int val = 5;
private:
int* ptr;
};
int main()
{
int x = 100;
Str ptr(&x);
std::cout << ptr->val << std::endl; //#1
std::cout << (ptr.operator->()->val) << std::endl; //#2 #1与#2等价
return 0;
}
struct Str2
{
Str2* operator->()
{
return this;
}
int blabla = 20;
};
struct Str
{
Str(int* p)
: ptr(p)
{}
Str2 operator ->() //类Str中重载->运算符返回Str2类对象
{
return Str2{};
}
int val = 5;
private:
int* ptr;
};
int main()
{
int x = 100;
Str ptr(&x);
std::cout << ptr->blabla << std::endl; //#1
std::cout << (ptr.operator->().operator->()->blabla) << std::endl; //#2 #1与#2等价
return 0;
}
int operator->() //Error: member type 'int' is not a pointer
{
return blabla;
}
int* operator->() //Error: member reference base type 'int' is not a structure or a union
{
return &blabla;
}
● 使用函数调用运算符构造可调用对象
struct Str
{
Str(int p)
: val(p)
{}
int operator()()
{
return val;
}
int operator()(int x, int y, int z) //参数列表不同,重载
{
return val + x + y +z;
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << obj() << std::endl;
std::cout << obj(1, 2, 3) << std::endl;
return 0;
}
struct Str
{
Str(int p)
: val(p)
{}
int& operator()()
{
return this->val;
}
bool operator()(int input) //参数依据实际情况修改,更加灵活,是Lambda表达式的基础
{
//return val < input;
return val++ < input;
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << obj() << std::endl;
std::cout << obj(1) << std::endl;
std::cout << obj() << std::endl;
std::cout << obj(199) << std::endl;
std::cout << obj() << std::endl;
return 0;
}
参考
深蓝学院:C++基础与深度解析