文章目录
- 1.类型转换运算符
- 2.->运算符
- 3.operator new、operator delete,new运算符的3种用法
1.类型转换运算符
- 必须是成员函数,不能是友元函数
- 没有参数(操作数是什么?)
因为操作数就是类对象自身 - 不能指定返回类型(其实已经指定了)
它要指定的类型就是返回类型 - 函数原型:
operator 类型名();
- eg:25cpp\25cpp\25cpp\01.cpp
#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;//通过转换构造函数Integer(int n);也叫构造函数,可以将200转换为类类型,赋值给n
n.Display();
int sum = add(n, 100);
cout<<sum<<endl;
int x = n;//隐式转换:调用类型转换运算符operator int();
int y = static_cast<int>(n);//显示转换,调用类型转换运算符operator int();
return 0;
}
- 类声明及定义
25cpp\25cpp\25cpp\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();//没有参数,就是将自身转换为int型
void Display() const;
private:
int n_;
};
#endif // _INTEGER_H_
25cpp\25cpp\25cpp\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;
}
- 测试:
2.->运算符
- eg:25cpp\25cpp\25cpp\02.cpp
#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()
{
//构造一个DBHelper对象
db_ = new DBHelper;
}
~DB()
{
delete db_;
}
//重载指针运算符->
//指针运算符重载返回一个内部的指针,然后通过内部的指针访问DBHelper的成员函数
DBHelper* operator->()
{
return db_;
}
private:
DBHelper* db_;//DBHelper对象,函数指针是db_
};
int main(void)
{
//利用类对象db确定析构机制,将它所包装的动态对象销毁掉
DB db;
db->Open();
db->Query();
db->Close();
return 0;
}
- 测试:
指针运算符重载
3.operator new、operator delete,new运算符的3种用法
- (1)operator new与之对应的delete操作是:
void* operator new(size_t size)
void operator delete(void* p)
New运算符重载,delete运算符也要被重载
void operator delete(void* p, size_t size)
与void operator delete(void* p)可以共存,先调用void operator delete(void* p)
- (2)这个operator new与之对应的delete操作是:
void* operator new(size_t size, const char* file, long line)
void operator delete(void* p, const char* file, long line)
void operator delete(void* p, size_t size, const char* file, long line)
两者是等价的,都出现时,上面的delete优先
- (3)针对数组而言,这个operator new与之对应的delete操作是:
void* operator new[](size_t size)
void operator delete[](void* p)
void operator delete[](void* p, size_t size)
- new有3种用法
(1)new operator:不能被重载
(2)operator new:可以被重载
(3)placement new
placement new是在已经申请的内存上构建对象. 这就是我们调用new的时候会调用对象的构造函数的原因。 - eg:25cpp\25cpp\25cpp\03.cpp
#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)
{
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<<file<<":"<<line<<endl;
void* p = malloc(size);
return p;
}
void operator delete(void* p, const char* file, long line)
{
//打印哪一个文件,哪一行
cout<<file<<":"<<line<<endl;
free(p);
}
void operator delete(void* p, size_t size, const char* file, long line)
{
cout<<file<<":"<<line<<endl;
free(p);
}
//placement new的用法如下:
//这是局部的 placement new,已经存在的内存地址,直接返回就可以了,内部不需要分配空间
//所以相应的delete不需要做任何的操作
void* operator new(size_t size, void* p)
{
return p;
}
void operator delete(void *, void *)
{
}
int n_;
};
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)
{
//new operator用法
Test* p1 = new Test(100); // 称作是:new operator,new operator = operator new内存分配 + 构造函数的调用
delete p1;
//这个是全局的operator new操作
char* str = new char[100];
delete[] str;
char chunk[10];
//placement new用法
//在chunk这块内存上进行new操作
//返回的是p2指针就等于chunk的地址
//p2的地址就等于chunk地址,4个字节的Test对象使用的空间就是chunk空间的4个字节
Test* p2 = new (chunk) Test(200); //operator new(size_t, void *_Where)
// placement new,不分配内存 + 构造函数的调用
cout<<p2->n_<<endl;
p2->~Test(); // 显式调用析构函数,析构函数可以被显式调用的
//不能使用delete p2,因为它不是堆上生成的内存,它的内存在已经存在的chunk内存中
//所以要使用显式调用析构函数的方式来调用
//强制转换
//Test* p3 = (Test*)chunk;等价于下面的类型转换
Test* p3 = reinterpret_cast<Test*>(chunk);
cout<<p3->n_<<endl;
//Test* p4 = new(__FILE__, __LINE__) Test(300);//传递的是operator new+构造函数的调用,operator不仅
//传递了对象的大小300,还传递了__FILE__, __LINE__
//delete(__FILE__, __LINE__) p4;delete p4(__FILE__, __LINE__);都没有调用与上面想对应的delete函数,后期有空可以研究下
//__FILE__表示这行所在的文件
//__LINE__表示这行所在的行号
#define new new(__FILE__, __LINE__)
Test* p4 = new Test(300);
delete p4;
return 0;
}
- 测试1:
Test* p1 = new Test(100); // 称作是:new operator,new operator = operator new内存分配 + 构造函数的调用
利用VS2008,跟踪一下,按下F9,
按下F11,调用operator new,传递了一个大小进来,当前类的大小是4个字节
按下shift F11可以跳出这个函数,或者按下F10不去跟踪这一行函数
- 测试2:
char chunk[10];
//placement new用法
//在chunk这块内存上进行new操作
//返回的是p2指针就等于chunk的地址
//p2的地址就等于chunk地址,4个字节的Test对象使用的空间就是chunk空间的4个字节
Test* p2 = new (chunk) Test(200); //operator new(size_t, void *_Where)
// placement new,不分配内存 + 构造函数的调用
cout<<p2->n_<<endl;
//强制转换
//Test* p3 = (Test*)chunk;
Test* p3 = reinterpret_cast<Test*>(chunk);
cout<<p3->n_<<endl;
F11,直接返回Where指针,Where的地址就是chunk的地址
再次按下F10
返回了一个存在的指针,构造的对象放在了chunk地址里面了
chunk地址与p2地址是一样的
- 测试3:测试的上面的(1)operate new的用法
- 测试4:
//这个是全局的operator new操作
char* str = new char[100];
delete[] str;
重载的是带数组的operator new:void* operator new[](size_t size)
- 测试5:测试的是上面(2)operate new的用法
void* operator new(size_t size)
{
cout<<"void* operator new(size_t size)"<<endl;
void* p = malloc(size);
return p;
}
。。。。
。。。。
。。。。
void operator delete(void *, void *)
{
}
将上述重载的new与delete的运算符全都屏蔽掉,进入debug,看到了应该与operator new相匹配的operator delete的原型
//Test* p4 = new(__FILE__, __LINE__) Test(300);//传递的是operator new+构造函数的调用,operator不仅
//传递了对象的大小300,还传递了__FILE__, __LINE__
//delete(__FILE__, __LINE__) p4;delete p4(__FILE__, __LINE__);都没有调用与上面想对应的delete函数,后期有空可以研究下
//__FILE__表示这行所在的文件
//__LINE__表示这行所在的行号
#define new new(__FILE__, __LINE__)
Test* p4 = new Test(300);
delete p4;
- 参考:new实现