类型转换运算符
- 必须是成员函数,不能是友元函数
- 没有参数
- 不能指定返回类型
- 函数原型:operator 类型名();
#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_
#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;
}
其中n = 200; 是隐式将int 转换成Interger类;int x = n; 是调用operator int 将Interger 类转换成int,也可以使用static_cast 办到;此外add 函数传参时也会调用operator int 进行转换。
*运算符重载,->运算符重载、
#include <iostream>
using namespace std;
class DBHelper
{
public:
DBHelper()
{
cout << "DB ..." << endl;
}
~DBHelper()
{
cout << "~DB ..." << endl;
}
void Open()
{
cout << "Open ..." << endl;
}
void Close()
{
cout << "Close ..." << endl;
}
void Query()
{
cout << "Query ..." << endl;
}
};
class DB
{
public:
DB()
{
db_ = new DBHelper;
}
~DB()
{
delete db_;
}
DBHelper *operator->()
{
return db_;
}
DBHelper &operator*()
{
return *db_;
}
private:
DBHelper *db_;
};
int main(void)
{
DB db;
db->Open();
db->Query();
db->Close();
(*db).Open();
(*db).Query();
(*db).Close();
return 0;
}
db->Open(); 等价于 (db.operator->())->Open(); 会调用operator-> 返回DBHelper类的指针,调用DBHelper的成员函数Open()。这样使用的好处是不需要知道db 对象什么时候需要释放,当生存期结束时,会调用DB类的析构函数,里面delete db_; 故也会调用DBHelper类的析构函数。(*db).Open(); 等价于(db.operator*()).Open();
operator new 和 operator delete
实际上new 有三种用法,包括operator new、new operator、placement new,new operator 包含operator new,而placement new 则没有内存分配而是直接调用构造函数。
#include <iostream>
using namespace std;
class Test
{
public:
Test(int n) : n_(n)
{
cout << "Test(int n) : n_(n)" << endl;
}
Test(const Test &other)
{
cout << "Test(const Test& other)" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
/****************************************************************/
void *operator new(size_t size)
{
cout << "void* operator new(size_t size)" << endl;
void *p = malloc(size);
return p;
}
void operator delete(void *p) //与下面的operator delete函数类似,共存的话优先;
{
//匹配上面的operator new 函数
cout << "void operator delete(void* p)" << endl;
free(p);
}
void operator delete(void *p, size_t size)
{
cout << "void operator delete(void* p, size_t size)" << endl;
free(p);
}
/**********************************************************************/
void *operator new(size_t size, const char *file, long line)
{
cout << " void* operator new(size_t size, const char* file, long line);" << endl;
cout << file << ":" << line << endl;
void *p = malloc(size);
return p;
}
void operator delete(void *p, const char *file, long line)
{
cout << " void operator delete(void* p, const char* file, long line);" << endl;
cout << file << ":" << line << endl;
free(p);
}
void operator delete(void *p, size_t size, const char *file, long line)
{
cout << "void operator delete(void* p, size_t size, const char* file, long line);" << endl;
cout << file << ":" << line << endl;
free(p);
}
/**************************************************************************/
void *operator new(size_t size, void *p)
{
cout << "void* operator new(size_t size, void* p);" << endl;
return p;
}
void operator delete(void *, void *)
{
cout << "void operator delete(void *, void *);" << endl;
}
/**************************************************************************/
int n_;
};
/*************** global **********************************************/
void *operator new(size_t size)
{
cout << "global void* operator new(size_t size)" << endl;
void *p = malloc(size);
return p;
}
void operator delete(void *p)
{
cout << "global void operator delete(void* p)" << endl;
free(p);
}
/**********************************************************************/
void *operator new[](size_t size)
{
cout << "global void* operator new[](size_t size)" << endl;
void *p = malloc(size);
return p;
}
void operator delete[](void *p)
{
cout << "global void operator delete[](void* p)" << endl;
free(p);
}
/***********************************************************************/
int main(void)
{
Test *p1 = new Test(100); // new operator = operator new + 构造函数的调用
delete p1;
char *str1 = new char;
delete str1;
char *str2 = new char[100];
delete[] str2;
char chunk[10];
Test *p2 = new (chunk) Test(200); //operator new(size_t, void *_Where)
// placement new,不分配内存 + 构造函数的调用
cout << p2->n_ << endl;
p2->~Test(); // 显式调用析构函数
//Test* p3 = (Test*)chunk;
Test *p3 = reinterpret_cast<Test *>(chunk);
cout << p3->n_ << endl;
#define new new(__FILE__, __LINE__)
//Test* p4 = new(__FILE__, __LINE__) Test(300);
Test *p4 = new Test(300);
delete p4;
return 0;
}
从输出可以看出几点:
1、new operator 是分配内存(调用operator new) + 调用构造函数
2、operator new 是只分配内存,不调用构造函数
3、placement new 是不分配内存(调用operator new(与2是不同的函数) 返回已分配的内存地址),调用构造函数
4、delete 是先调用析构函数,再调用operator delete.
5、如果new 的是数组,对应地也需要delete [] 释放
注意:
1、如果存在继承或者对象成员,那么调用构造函数或者析构函数时将有多个,按一定顺序调用。
2、假设存在继承,delete 基类指针;涉及到虚析构函数的问题。
最后一点是 delete p4 为什么调用的不是 void operator delete(void* p, const char* file, long line); 而是void operator delete(void* p)
当两个operator new和operator delete有相等的参数个数,并且除了第一个参数之外其余参数的类型依次完全相同之时,我们称它们为一对匹配的operator new和operator delete。 不过正常情况下带多个参数的delete不会被调用,只有在构建一个对象的过程中,构造函数中发生异常,并且这个异常被捕获了,那么此时C++的异常处理机制才会自动用与被使用的operator new匹配的operator delete来释放内存(补充一点:在operator new中抛出异常不会导致这样的动作,因为系统认为这标志着内存分配失败)。编译期间编译器按照以下顺序寻找匹配者:首先在被构建对象类的类域中寻找,然 后到父类域中,最后到全局域,此过程中一旦找到即停止搜寻并用它来生成正确的内存释放代码,如果没有找到,当发生上述异常情况时将不会有代码用来释放分配 的内存,这就造成内存泄漏了。
#include <malloc.h>
struct Base
{
Base()
{
throw int(3);
}
~Base() {}
void* operator new( size_t nSize, const char*,int)
{
void* p = malloc( nSize );
return p;
}
void operator delete( void *p)
{
free(p);
}
void operator delete( void* p,const char*,int)
{
free( p );
}
};
#define new new(__FILE__, __LINE__)
int main( void )
{
Base* p = null;
try
{
p = new Base;
delete p;
}
catch(...)
{
}
return 0;
}