4.运算符重载
运算符重载的两种方法:
- 全局函数
- 成员函数
基础的有一元、二元、加减、++和–。
运算符原有意义没有失去,只是定义了某类的新运算符。
运算符重载的本质是函数调用。
运算符函数可以重载为成员函数或友元函数,区别是有无this。
c3 = operator+(c1,c2);
c3 = c1.operator+(c2);
一元运算符相对二元运算符的重载更复杂.
istream
和ostream
是c++的预定义流类,它们的左移右移操作符,左侧运算量是 cin或cout 而不是对象本身,我们只能用友元函数重载。
cin/cout
是istream/ostream
的对象.
friend ostream& operator<<(ostream &out, Complex &c);
cout<<c1<<endl;
左右移的运行顺序是从左到右的,所以上面两行就相当于
operator<<(cout,c1).operator<<(endl);
所以返回类型是ostream&
复数类示例
#include<iostream>
using namespace std;
class Complex{
public:
Complex(){
this->x = 0;
this->y = 0;
}
Complex(int x, int y){
this->x = x;
this->y = y;
}
Complex(const Complex &c){
cout<<"copy"<<endl;
}
void print(){
if(y < 0)
cout<<x<<y<<"i"<<endl;
else
cout<<x<<"+"<<y<<"i"<<endl;
}
Complex operator+(Complex &c2){
Complex c(this->x + c2.x, this->y + c2.y);
return c;
}
friend Complex operator-(Complex &c1 , Complex &c2);
//前置++,--
friend Complex& operator++(Complex &c);
Complex& operator--(){
this->x--;
this->y--;
return *this;
}
//后置++,--
friend Complex operator++(Complex &c , int);
Complex operator--(int){
Complex tmp = *this; //copy
this->x--;
this->y--;
return tmp;
}
friend ostream& operator<<(ostream &out, Complex &c);
private:
int x,y;
};
/*
Complex operator+(Complex &c1 , Complex &c2){
Complex c(c1.getX() + c2.getX(), c1.getY() + c2.getY());
return c;
}
*/
Complex operator-(Complex &c1 , Complex &c2){
Complex c(c1.x - c2.x, c1.y - c2.y);
return c;
}
Complex& operator++(Complex &c){ //前置++
c.x++;
c.y++;
return c;
}
Complex operator++(Complex &c , int){ //后置++
Complex tmp = c; //copy
c.x++;
c.y++;
return tmp;
}
ostream& operator<<(ostream &out, Complex &c){
if(c.y < 0)
out<<c.x<<c.y<<"i"<<endl;
else
out<<c.x<<"+"<<c.y<<"i"<<endl;
return out;
}
int main(int argc, char *argv[])
{
Complex c1(1,2),c2(3,4);
Complex c3;
cout<<" c3 = operator+(c1,c2)"<<endl;
//c3 = operator+(c1,c2);
//c3.print();
cout<<endl;
cout<<" c3 = c1 + c2"<<endl;
c3 = c1 + c2;
c3.print();
cout<<endl;
cout<<" Complex c4 = operator-(c1,c2)"<<endl;
Complex c4 = operator-(c1,c2);
c4.print();
cout<<endl;
cout<<" c4 = c1 - c2"<<endl;
c4 = c1 - c2;
c4.print();
cout<<endl;
cout<<" operator++(c1)"<<endl;
operator++(c1);
c1.print();
cout<<" ++c1"<<endl;
++c1;
c1.print();
cout<<endl;
cout<<" --c1"<<endl;
--c1;
c1.print();
cout<<endl;
cout<<" c1++;"<<endl;
c1++;
c1.print();
cout<<endl;
cout<<" c1--;"<<endl;
c1--;
c1.print();
cout<<endl;
cout<<" operator<<(cout,c1).operator<<(endl); "<<endl;
//cout.operator<<(cout,c1).operator<<endl;
cout<<" cout<<c1<<endl; "<<endl;
cout<<c1<<endl;
cin.get();
return 0;
}
成员函数重载
4种不能用友元函数重载的操作符:
=
()
[]
->
等号重载注意:
- 释放旧内存
- 返回一个引用
等号运算顺序是从右到左
()
和[]
等都是二元运算符,只能用成员函数重载,不能用友元函数重载。
/*
等号重载
*/
#include<iostream>
#include<string>
using namespace std;
class Person{
public:
Person(const char* name, int age){
this->name = (char*)malloc(strlen(name) + 1);
strcpy(this->name, name);
this->age = age;
}
Person& operator=(Person& p){
char *tmpP;
if(this->name != NULL){
//delete[] this->name;
tmpP = this->name;
this->name = NULL;
}
this->name = (char*)malloc(strlen(p.name) + 1);
strcpy(this->name, p.name);
free(tmpP);
tmpP = NULL;
this->age = p.age;
return *this;
}
void printAddr(){
printf("%p\n",this->name);
}
private:
char *name;
int age;
};
int main(int argc, char *argv[])
{
Person p1("foo",1),p2("bar",2);
Person p3("abc",3);
p1.printAddr();
p2.printAddr();
p3.printAddr();
p1 = p2 = p3;
cout<<endl;
p1.printAddr();
p2.printAddr();
p3.printAddr();
cin.get();
return 0;
}
#include<iostream>
#include<string>
using namespace std;
class Person{
public:
Person(int i){
this->name = new char[i];
}
Person(const Person& p){
cout<<"copy"<<endl;
}
void setName(const char* name){
if(this->name != NULL){
free(this->name);
this->name = NULL;
}
this->name = (char*)malloc(sizeof(strlen(name)) + 1);
strcpy(this->name,name);
}
int getNameLen(){
return strlen(this->name);
}
char& operator[](int i);
Person& operator=(Person& p);
bool operator==(Person &p);
bool operator!=(Person &p);
private:
char *name;
};
// [] 重载
char& Person::operator[](int i){
return this->name[i];
}
Person& Person::operator=(Person& p){
if(this->name != NULL){
free(this->name);
this->name = NULL;
}
this->name = (char*)malloc(sizeof(strlen(p.name)) + 1);
strcpy(this->name,p.name);
return *this;
}
bool Person::operator==(Person &p){
return !strcmp(this->name,p.name);
}
bool Person::operator!=(Person &p){
return !(*this == p);
//return strcmp(this->name,p.name);
}
int main(int argc, char *argv[])
{
Person p1(10);
p1.setName("foobar");
for(int i = 0 ; i < p1.getNameLen() ; i++){
printf("%c",p1[i]);
}
for(int i = 0 ; i < p1.getNameLen() ; i++){
printf("%c",p1.operator[](i));
}
cout<<endl;
Person p2 = p1; //disiplay "copy"
p2.operator=(p1);
p2 = p1;
for(int i = 0 ; i < p2.getNameLen() ; i++){
printf("%c",p2[i]);
}
cout<<endl;
cout<<endl;
if(p1 == p2) cout<<"p1==p2"<<endl;
if(p1.operator==(p2)) cout<<"p1==p2"<<endl;
p2.setName("abcdef");
if(p1 != p2) cout<<"p1!=p2"<<endl;
if(p1.operator!=(p2)) cout<<"p1!=p2"<<endl;
cin.get();
return 0;
}
对象带括号,可能是构造,也可能是重载。
#include<iostream>
using namespace std;
class MyClass{
private:
public:
int operator()(int a, int b){
return a+b;
}
};
int main(int argc, char *argv[])
{
MyClass c;
int a = c(1,2);
cout<<a<<endl;
cin.get();
return 0;
}
关于&&和||
不要重载&&
和||
它们有短路规则,从左到右执行,重载的话会破坏这个规则。
例如:obj1 && (obj1 + obj2)
它会先执行加号。
即使这样写
(obj1 + obj2) && obj1
如果左边为假,还是会执行&&,破坏了短路规则。
#include<iostream>
using namespace std;
class T{
public:
int i;
T(int i){
this->i = i;
}
T operator+(const T &o){
T t(0);
t.i = this->i + o.i;
cout<<"exec +"<<endl;
return t;
}
bool operator&&(const T& o){
cout<<"exec && func."<<endl;
return this->i && o.i;
}
};
int main(int argc, char *argv[])
{
T t1(0),t2(1);
if( t1 && (t1 + t2) ){
cout<<"t1 && (t1 + t2):true"<<endl;
}
t2.i= 0;
if( (t1 + t2) && t1 ){
cout<<"(t1 + t2) && t1:true"<<endl;
}
cin.get();
return 0;
}
MyString类示例
/*
MyString.h
*/
#pragma once
#include<iostream>
using namespace std;
class MyString{
private:
int len;
char *p;
public:
MyString();
MyString(const char *s);
MyString(int n);
MyString(const MyString& s);
~MyString();
char* getP() const;
char& operator[](int index);
MyString& operator=(const char*s);
MyString& operator=(const MyString &s);
friend ostream& operator<<(ostream &out, MyString &s);
friend istream& operator>>(istream &out, MyString &s);
bool operator==(const char* s) const;
bool operator==(const MyString& s) const;
bool operator!=(const char* s) const;
bool operator!=(const MyString& s) const;
bool operator<(const char* s);
bool operator<(const MyString& s);
bool operator>(const char* s);
bool operator>(const MyString& s);
int getL() const;
void print();
};
/*
MyString.cpp
*/
#include "MyString.h"
MyString::MyString(){
len = 0;
p = new char[len+1];
strcpy(p,"");
}
MyString::MyString(const char *s){
if( s == NULL){
len = 0;
p = new char[len+1];
strcpy(p,"");
}
else{
len = strlen(s);
p = new char[len+1];
strcpy(p,s);
}
}
MyString::MyString(int n){
if(n == 0){
len = 0;
p = new char[len + 1];
strcpy(p,"");
}
else{
len = n;
p = new char[len + 1];
memset(p,0,len);
}
}
char* MyString::getP() const{
return this->p;
}
int MyString::getL() const{
return this->len;
}
MyString::MyString(const MyString& s){
if(p != NULL){
delete[] p;
p = NULL;
}
len = s.getL();
p = new char[len+1];
strcpy(p,s.getP());
}
MyString::~MyString(){
if(p != NULL){
delete[] p;
p = NULL;
len = 0;
}
}
char& MyString::operator[](int index){
return p[index];
}
MyString& MyString::operator=(const char*s){
if( p != NULL ){
delete[] p;
len = 0;
}
if( s == NULL ){
len = 0;
p = new char[len+1];
strcpy(p,"");
}
else{
len = strlen(s);
p = new char[len+1];
strcpy(p,s);
}
return *this;
}
MyString& MyString::operator=(const MyString &s){
if( p != NULL ){
delete[] p;
len = 0;
}
len = s.getL();
p = new char[len+1];
strcpy(p,s.getP());
return *this;
}
ostream& operator<<(std::ostream &out, MyString &s){
out<<s.getP();
return out;
}
bool MyString::operator==(const char* s) const{
if(s == NULL){
if(len == 0){
return true;
}
else
{
return false;
}
}
else{
if(len == strlen(s)){
return !strcmp(p,s);
}
else
{
return false;
}
}
}
bool MyString::operator!=(const char* s) const{
return !(*this == s);
}
bool MyString::operator==(const MyString& s) const{
if(len != s.getL()){
return false;
}
else{
return !strcmp(p,s.getP());
}
}
bool MyString::operator!=(const MyString& s) const{
if(len != s.getL()){
return true;
}
else{
return p != s.getP();
}
}
bool MyString::operator<(const char* s){
int ret = strcmp(p,s);
if(ret < 0){
return true;
}
else{
return false;
}
}
bool MyString::operator>(const char* s){
int ret = strcmp(p,s);
if(ret > 0){
return true;
}
else{
return false;
}
}
bool MyString::operator<(const MyString& s){
return p<s.getP();
}
bool MyString::operator>(const MyString& s){
return p>s.getP();
}
istream& operator>>(istream &out, MyString &s){
cin>>s.getP();
return out;
}
void MyString::print(){
cout<<p<<endl;
}
/*
main.cpp
*/
#include<cstdlib>
#include<cstring>
#include "MyString.h"
using namespace std;
int main(int argc, char *argv[])
{
MyString s1;
MyString s2("abc");
MyString s3 = s2;
s1.print();
s2.print();
s3.print();
s3[0] = 'b';
MyString s4 = "def";
s3.print();
s4.print();
cout<<s4<<endl;
MyString s5 = s4;
if(s5 == s4){
cout<<"s5==s4"<<endl;
}
else{
cout<<"s5!=s4"<<endl;
}
if(s5 != s3){
cout<<"s5!=s3"<<endl;
}
else{
cout<<"s5==s3"<<endl;
}
if(s1 == NULL){
cout<<"s1 == NULL"<<endl;
}
else{
cout<<"s1 != NULL"<<endl;
}
cout<<(s5<"a")<<endl;
cout<<(s5>"a")<<endl;
cout<<(s5<s2)<<endl;
//cout<<(s5<NULL)<<endl;
MyString s6(10);
cin>>s6;
cout<<s6<<endl;
cin.get();
return 0;
}