- 运算符重载
运算符重载允许把标准运算符(如+、—、*、/、<、>等)应用于自定义数据类型的对象;直观自然,可以提高程序的可读性;体现了C++的可扩充性;运算符重载仅仅只是语法上的方便,它是另一种函数调用的方式;运算符重载,本质上是函数重载;不要滥用重载、因为它只是语法上的方便,所以只有在涉及的代码更容易写、尤其是更易读时才有必要重载。 -
成员函数重载
成员函数原型的格式:
函数类型 operator 运算符(参数表);
成员函数定义的格式:
函数类型 类名::operator 运算符(参数表) {
函数体;
}
一个复数+运算符以成员函数重载的例子
class Complex { public: Complex(int real, int imag) : real_(real), imag_(imag) { } Complex operator+(const Complex &other) { int r = real_ + other.real_; int i = imag_ + other.imag_; return Complex(r, i); } void display() { cout << real_ << "+" << imag_ << "i" << endl; } private: int real_; int imag_; }; int main(void) { Complex c1(1, 2); Complex c2(2, 3); Complex c3 = c1 + c2; // 等价于c3 = c1.operator+(c2) c3.display(); return 0; }
-
非成员函数重载
友元函数原型的格式:
friend 函数类型 operator 运算符(参数表);
友元函数定义的格式:
函数类型 operator 运算符(参数表){
函数体;
}
一个复数+运算符以有元函数重载的例子
class Complex { friend Complex operator+(const Complex &c1, const Complex &c2); public: Complex(int real, int imag) : real_(real), imag_(imag) { } void display() { cout << real_ << "+" << imag_ << "i" << endl; } private: int real_; int imag_; }; Complex operator+(const Complex &c1, const Complex &c2) { int r = c1.real_ + c2.real_; int i = c1.imag_ + c2.imag_; return Complex(r, i); } int main(void) { Complex c1(1, 2); Complex c2(2, 3); Complex c3 = c1 + c2; c3.display(); return 0; }
-
运算符重载规则
运算符重载不允许发明新的运算符。不能改变运算符操作对象的个数。运算符被重载后,其优先级和结合性不会改变。不能重载的运算符:
作用域解析运算符(::),条件运算符(?:),直接成员访问运算符(.),类成员指针引用的运算符(.* ),sizeof运算符。
一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。以下一些双目运算符不能重载为类的友元函数:=(比如把基类赋值给基类)、()、[]、->。类型转换运算符只能以成员函数方式重载流运算符只能以友元的方式重载
- ++运算符重载
前置++运算符重载
成员函数的方式重载,原型为:
函数类型 & operator++();
友元函数的方式重载,原型为:
friend 函数类型 & operator++(类类型 &);
后置++运算符重载
成员函数的方式重载,原型为:
函数类型 & operator++(int);
友元函数的方式重载,原型为:
friend函数类型 & operator++(类类型 &,int);
案例代码
class Integer{ public: Integer(int num = 0) : num_(num) { } // 前置++ /*Integer & operator++() { ++num_; return *this; }*/ // 这里有元重载和成员函数重载不能共存,不像+ friend Integer & operator++(Integer &it) { ++it.num_; return it; } // 后置++,返回对象,非引用 /*Integer operator++(int i) { Integer it(num_); num_++; return it; }*/ friend Integer operator++(Integer &it, int i) { Integer itm(it.num_); it.num_++; return itm; } void display() { cout << num_ << endl; } private: int num_; }; int main(void) { Integer it1(10); Integer it2 = ++it1; it1.display(); // 11 it2.display(); // 11 Integer it3 = it1++; it1.display(); // 12 it3.display(); // 11 return 0; }
-
!运算符重载
一个String类中!运算符重载的实现
bool operator!() { return strlen(str_) == 0; } friend bool operator!(String &st) { return strlen(st.str_) == 0; }
-
赋值运算符重载
一个String类中=重载的实现
class String { public: explicit String(const char *str="") { str_ = allocAndCpy(str); } String(const String &str) { str_ = allocAndCpy(str.str_); } char *allocAndCpy(const char *str) { char *s = NULL; int len = strlen(str) + 1; s = new char[len]; memset(s, 0, len); strcpy(s, str); return s; } bool operator!() { return strlen(str_) == 0; } friend bool operator!(String &st) { return strlen(st.str_) == 0; } String& operator=(const String &other) { if (this == &other) return *this; delete[]str_; str_ = allocAndCpy(other.str_); return *this; } String& operator=(const char *str) { delete[]str_; str_ = allocAndCpy(str); return *this; } void display() { cout << str_ << endl; } ~String() { delete[]str_; } private: char *str_; }; int main(void) { String st("AAAAA"); String st2; st2 = st; st2.display(); st2 = "BBBB"; // 没在构造函数前加explict前,会调用构造函数,生成临时对象, // 加上explicit关键字,重载=(const char *str)即可 st2.display(); return 0; }
- String类实现
[]运算符重载-必须重载成成员函数+运算符重载-使用+=运算符重载优化代码+=运算符重载<<运算符重载-必须重载成有元函数>>运算符重载-必须重载成有元函数
实现代码
String.h:
// String.h #ifndef __STRING_H__ #define __STRING_H__ #include <iostream> using namespace std; class String { public: explicit String(const char *str = ""); String(const String &str); char *allocAndCpy(const char *str) const; bool operator!() const; friend bool operator!(String &st); String &operator=(const String &other); String &operator=(const char *str); void display() const; char &operator[](int index) const; //friend char &operator[](String &st, int index); // 不能把[]以有元重载 //String operator+(const String &other) const; friend String operator+(const String &st, const String &other); //String &operator+=(const String &other); friend String &operator+=(String &st, const String &other); friend ostream &operator<<(ostream &os, const String &st); friend istream &operator>>(istream &is, String &st); ~String(); private: char *str_; }; #endif // __STRING_H__
String.cpp:
// String.cpp #define _CRT_SECURE_NO_WARNINGS #include "String.h" #include <cstring> String::String(const char *str) { str_ = allocAndCpy(str); } String::String(const String &str) { str_ = allocAndCpy(str.str_); } char *String::allocAndCpy(const char *str) const { char *s = NULL; int len = strlen(str) + 1; s = new char[len]; memset(s, 0, len); strcpy(s, str); return s; } bool String::operator!() const { return strlen(str_) == 0; } bool operator!(String &st) { return strlen(st.str_) == 0; } String& String::operator=(const String &other) { if (this == &other) return *this; delete[]str_; str_ = allocAndCpy(other.str_); return *this; } String& String::operator=(const char *str) { delete[]str_; str_ = allocAndCpy(str); return *this; } void String::display() const { cout << str_ << endl; } // 返回引用,给函数赋值,比如a[0] = 10; char &String::operator[](int index) const { return str_[index]; } //String String::operator+(const String &other) const //{ // int len = strlen(str_) + strlen(other.str_) + 1; // char *newstr = new char[len]; // strcpy(newstr, str_); // strcat(newstr, other.str_); // String tmp(newstr); // delete[]newstr; // // return tmp; //} // 以有元方式重载+,当成员函数重载也存在,并且有元的参数为const,那么+默认调用有元方式重载 // 一旦加了const,那么就调用不明确了 String operator+(const String &st, const String &other) { /*int len = strlen(st.str_) + strlen(other.str_) + 1; char *newstr = new char[len]; strcpy(newstr, st.str_); strcat(newstr, other.str_); String tmp(newstr); delete[]newstr;*/ // 优化直接调用+= String tmp(st); tmp += other; return tmp; } //String &String::operator += (const String &other) //{ // int len = strlen(str_) + strlen(other.str_) + 1; // char *newstr = new char[len]; // strcpy(newstr, str_); // strcat(newstr, other.str_); // str_ = newstr; // // return *this; //} String &operator+=(String &st, const String &other) { int len = strlen(st.str_) + strlen(other.str_) + 1; char *newstr = new char[len]; strcpy(newstr, st.str_); strcat(newstr, other.str_); st.str_ = newstr; return st; } ostream &operator << (ostream &os, const String &st) { os << st.str_ << endl; return os; } istream &operator>>(istream &is, String &st) { char tmp[1024]; cin >> tmp; st = tmp; return is; } String::~String() { delete[]str_; }
测试代码:
// 测试代码 #define _CRT_SECURE_NO_WARNINGS #include "String.h" #include <cstring> int main(void) { String st("AAAAA"); String st2; st2 = st; st2.display(); st2 = "BBBB"; // 没在构造函数前加explict前,会调用构造函数,生成临时对象, // 加上explicit关键字,重载=(const char *str)即可 st2.display(); // 重载[] cout << st[2] << endl; st[2] = 'C'; st.display(); // 重载+ String st3 = st + st2; st3.display(); // 重载+= st += st2; st.display(); // 重载<< cout << st << endl; // 重载<< cin >> st; cout << st << endl; return 0; }
-
类型转换运算符重载
必须是成员函数,不能是友元函数没有参数(操作数是什么?)不能指定返回类型(其实已经指定了)函数原型:operator 类型名();
一个Integer类转换成int类型的类型转换运算符的重载:
Integer.h:
#ifndef _INTEGER_H_ #define _INTEGER_H_ class Integer { public: Integer(int n); ~Integer(); Integer& operator++(); //friend Integer& operator++(Integer& i); Integer operator++(int n); //friend Integer operator++(Integer& i, int n); operator int(); void Display() const; private: int n_; }; #endif // _INTEGER_H_
Integer.cpp:
#include "Integer.h" #include <iostream> using namespace std; Integer::Integer(int n) : n_(n) { } Integer::~Integer() { } Integer& Integer::operator ++() { //cout<<"Integer& Integer::operator ++()"<<endl; ++n_; return *this; } //Integer& operator++(Integer& i) //{ // //cout<<"Integer& operator++(Integer& i)"<<endl; // ++i.n_; // return i; //} Integer Integer::operator++(int n) { //cout<<"Integer& Integer::operator ++()"<<endl; //n_++; Integer tmp(n_); n_++; return tmp; } //Integer operator++(Integer& i, int n) //{ // Integer tmp(i.n_); // i.n_++; // return tmp; //} Integer::operator int() { return n_; } void Integer::Display() const { cout<<n_<<endl; }
测试代码:
#include "Integer.h" #include <iostream> using namespace std; int add(int a, int b) { return a + b; } int main(void) { Integer n(100); n = 200; n.Display(); int sum = add(n, 100); cout<<sum<<endl; int x = n; int y = static_cast<int>(n); return 0; }
- ->运算符重载
(通过栈上的对象控制堆上的对象的内存释放)
class DBHelper { public: DBHelper() { cout << "DBHelper() ... " << endl; } ~DBHelper() { cout << "~DBHelper() ... " << endl; } void Open() { cout << "Open() ... " << endl; } void Close() { cout << "Close() ... " << endl; } void Query() { cout << "Query() ... " << endl; } private: int num_; }; class DB { public: DB() { cout << "DB() ..." << endl; helper_ = new DBHelper; } ~DB() { cout << "~DB() ..." << endl; delete helper_; } // 重载->实现DB对象析构时自动释放DBHelper的空间 DBHelper* operator->() { return helper_; } private: DBHelper *helper_; }; int main(void) { // 一旦重载了->,对象也能使用->操作了 // 有点智能指针的影子,通过栈上的对象去控制堆上的对象 DB db; db->Open(); db->Query(); db->Close(); return 0; }
- operator new、operator delete、placement new 深入
#include <iostream> #include <cstdio> using namespace std; class Test { public: Test(int num = 0) : num_(num) { cout << "Test(int num = 0) ..." << endl; } ~Test() { cout << "~Test() ... " << endl; } // 1.operator new void *operator new (size_t size) { Test *p = (Test *)malloc(size); return p; } // 2.placement new void *operator new (size_t size, void *p) { return p; } // 3.三个参数的new void *operator new (size_t size, const char *file, long line) { Test *p = (Test *)malloc(size); cout << "file:" << file << "-" << line << " line" << endl; return p; } void *operator new[](size_t size) { Test *p = (Test *)malloc(size); return p; } // 1.operator delete void operator delete (void *p) // 默认调用,要或者释放了多少个字节,可以重载为下面的函数 { free(p); } // 1.operator delete void operator delete (void *p, size_t size) { free(p); cout << "size=" << size << endl; } // 2.placement delete when 当placement new初始化引发异常 void operator delete (void *, void *) { // do nothing } // 3.三个参数的delete void operator delete (void *p, const char *file, long line) { free(p); } // 根据以上,还可以有四个参数的delete /*void operator delete (void *p, size_t size, const char *file, long line) { free(p); cout << "4 par: size=" << size << endl; }*/ int num_; }; void *operator new[] (size_t size) { int *p = (int *)malloc(size); return p; //Test *p = (Test *)malloc(size); //return p; } // 一个参数delete[] void operator delete[](void *p) { free(p); } // 两个参数的delete[],一样只是想得到析构的字节数,貌似就算注释掉一个参数的delete[]也不会调用这个两个参数的 //void operator delete[](void *p, size_t size) //{ // free(p); // cout << "[] size=" << size << endl; //} int main(void) { Test *t1 = new Test; // new operator = operator new + 构造函数 delete t1; // delete operator = operator delete + 析构函数 char buf[10]; // 分配内存不使用 Test *t2 = new (buf)Test(10); // placement new = operator new + 构造函数,调用 void * operator new(size_t, void *_Where)类型的函数 Test *p = reinterpret_cast<Test *>(buf); // 或者使用传统的强制转换 //Test *q = static_cast<Test *>(buf); // static_cast转换无效 cout << p->num_ << endl; // 10, 在buf的内存空间上来保存*t2 p->~Test(); // 手动调用析构函数的原因是,因为placement new会自动调用构造函数肯能分配了内存,必须调用析构函数释放 // delete []t2; // 本身就是栈上的对象不需要去释放,强制delete直接报错 Test *t3 = new (__FILE__, __LINE__) Test(10); // 检测哪个文件哪一行分配了内存,调用3个参数的new delete t3; // new [] delete[] 重载部分,使用全局的来重载,仅仅是简单演示 int *p1 = new int[10]; // delete[]p1; /*Test *t4 = new Test[10]; delete[]t4;*/ // 当全局也重载了,去调用成员函数中的new [] return 0; }
转载于:https://www.cnblogs.com/ifpelset/articles/4515723.html