重载运算符是具有特殊名字的函数,它们的关键字operator和其后要定的运算符号共同组成。现在就让我们了解一下c++的重载运算吧。
一.输入和输出运算符
class Person {
friend std::ostream& operator<<(std::ostream& os, const Person& person);
public:
Person() {};
Person(int he, int we, const std::string& names) :height(he), weight(we), name(new std::string(names)) {};
~Person() { delete name; };
private:
int height;
int weight;
std::string *name;
};
std::ostream& operator<<(std::ostream& os, const Person& person) {
os << person.height << " " << person.weight << " " << person.name->c_str();
return os;
}
int main(void)
{
Person person(170, 120, "Jay");
std::cout << person;
return 0;
}
operator<<的第一个形参必须是ostream类型,而且必须是非const引用类型。为什么呢?因为输出流是个动态过程,IO操作是不能copy的。第二个形参是const引用的类类型。为什么呢?因为打印类的状态,我们要求它是不能改变的,而且打印的是对象本身,而不是对象的副本。所以返回ostream的引用。
class Person {
friend std::istream& operator>>(std::istream& is, Person& person);
private:
int height;
int weight;
};
std::istream& operator>>(std::istream& is, Person& person) {
is >> person.height >> person.weight;
return is;
}
int main(void)
{
Person person;
std::cin >> person;
return 0;
}
operator>>的第一个参数必须是istream类型,而且必须是非const引用类型。为什么呢?因为输入流是个动态过程,IO操作是不能copy。第二个参数是非const引用的类类型。为什么呢?因为类的属性或者状态是在改变的。
二.算数运算符
class Person {
friend const Person operator+(const Person& person1, const Person& person2);
friend const Person operator-(const Person& person1, const Person& person2);
public:
Person() {};
Person(int he, int we) :height(he), weight(we) {};
private:
int height;
int weight;
};
const Person operator+(const Person& person1, const Person& person2) {
return Person(person1.height + person2.height, person2.weight + person2.weight);
}
const Person operator-(const Person& person1, const Person& person2) {
return Person(person1.height - person2.height, person2.weight - person2.weight);
}
int main(void)
{
Person person1(170, 120);
Person person2(175, 100);
Person person3 = person1 + person2;
Person person4 = person1 - person2;
return 0;
}
重载的算术运算符的形参都是const的类类型引用,为什么呢?因为一般不需要改变对象的状态,所以形参都是常量的引用。
三.关系运算符
class Person {
friend bool operator==(const Person& person1, const Person& person2);
friend bool operator> (const Person& person1, const Person& person2);
friend bool operator< (const Person& peraon1, const Person& person2);
friend bool operator!=(const Person& person1, const Person& person2);
public:
Person(int he, int we) :height(he), weight(we) {};
private:
int height;
int weight;
};
bool operator==(const Person& person1, const Person& person2) {
return person1.height == person2.height && person2.weight == person2.weight;
}
bool operator> (const Person& person1, const Person& person2) {
return person1.height > person2.height && person1.weight > person2.weight;
}
bool operator< (const Person& person1, const Person& person2) {
return person1.height < person2.height && person1.weight < person2.weight;
}
bool operator!=(const Person& person1, const Person& person2) {
return !(person1 == person2);
}
int main(void)
{
Person person1(170, 100);
Person person2(165, 120);
if (person1 == person2)
std::cout << "operator==";
if (person1 != person2)
std::cout << "operator!=";
if (person1 > person2)
std::cout << "operator>";
if (person1 < person2)
std::cout << "operator>";
return 0;
}
四.赋值运算符
class Person {
public:
Person(int he_=0, int we_=0) :height(he_), weight(we_) {};
Person& operator=(const Person& rhs) {
if (this == &rhs)
return *this;
else {
height = rhs.height;
weight = rhs.weight;
}
return *this;
}
void print() {
std::cout << "height:" << height << " " << "weight:" << weight;
}
private:
int height;
int weight;
};
int main(void)
{
Person person(170, 100);
Person person_;
person_ = person;
person.print();
return 0;
}
赋值运算符往往要定义为类的成员函数。
五.下标运算符
class Person {
public:
Person(std::string* na_ = 0) :name(na_) {};
std::string& operator[](std::size_t n) {
return name[n];
}
/*const std::string& operator[](std::size_t n) {
return name[n];
}*/
void print() {
std::cout << name->c_str();
}
private:
std::string* name;
};
int main(void)
{
std::string name = "Jay";
Person person(&name);
person.print();
return 0;
}
下表运算符有两个版本:一个返回普通引用。另一个是类的常量成员并返回常量引用。
六.递增递减运算符
class Person {
public:
Person(int he_) :height(he_) {};
Person& operator++() {
height += 1;
return *this;
}
Person& operator--() {
height -= 1;
return *this;
}
Person operator++(int) {
Person rhs = *this;
height += 1;
return rhs;
}
Person operator--(int) {
Person rhs = *this;
height -= 1;
return *this;
}
void print() {
std::cout << height << "\n";
}
private:
int height;
};
int main(void)
{
Person person(170);
++person; person.print();
person++; person.print();
--person; person.print();
person--; person.print();
return 0;
}
定义递增和递减运算符的类应该同时定义前置版本和后置版本。后置版本的int形参只具有区分作用,所以无须为其命名。
七.成员访问运算符
class Person {
public:
Person(std::string* na_ = 0) :name(na_) {};
std::string& operator*() {
return *name;
}
std::string* operator->() {
return name;
}
void print() {
std::cout << name->c_str();
}
private:
std::string* name;
};
int main(void)
{
std::string name = "Jay";
Person person(&name);
person.print();
return 0;
}
为什么operator*()的返回值是std::string& 呢? 因为std::string* 意为其指针指向的对象是可以改变的,所以不能是std::string。
八.函数调用运算符
class Person {
public:
Person(const std::string& na = std::string()) :name(new std::string(na)) {};
~Person() { delete name; };
void operator()(const std::string& name) {
std::cout << name.c_str();
}
private:
std::string* name;
};
int main(void)
{
Person person;
person("Jay");
return 0;
}
我们可以像使用函数一样使用该对象(函数对象),此时的类也能存储状态。
九.类型转换运算符
class Tree {
public:
Tree(const std::string& str=std::string()) :name(new std::string(str)) {};
~Tree() { delete name; };
operator std::string() const { //operator type() const{};
return *name;
}
private:
std::string* name;
};
int main(void)
{
std::string name = "Jay";
Tree tree(name);
std::cout << tree.operator std::string().c_str();
}
类型转换运算符可以面向任意的类型进行定义,只要该类型能作为函数的返回类型。类型转换运算符必须类的成员函数,不能声明返回类型,参数列表也必须为空,通常应该是const,因为类型转换运算符只起转换作用,而不改变类的数据成员变量。