更多的重载

更多的重载

  • 重载类型转换

  • 重载内存分配释放

  • 重载递增递减

重载类型转换

实现类型转变运算符

  • 类型转换运算符只能重载为类的成员函数

  • 类型转换运算符没有返回值,他的返回值由类型转换的类型来决定

  • 语法:operator 类型()const

hstring::operator int()
{
	int val{ 0 };

	//int i 标尺
	//cstr[0]='-',i=1;   cstr[0]!='-',i=0
	int i = cstr[0] == '-';

	while (cstr[i] >= '0' && cstr[i] <= '9')
	{
		val = val * 10 + cstr[i++] - 48;
	}

	//val=val*((表达式)*2-1),在有负号时表达式为0,无负号时表达式为1
	val = val * ((cstr[0] != '-') * 2 - 1); 

	return val;
}

int main()
{
	hstring str{ "123" };
	str = str + 456;
	int x = (int)str;
	std::cout << x;//123456
}

解决隐式类型转换带来的多义性问题

在类型转换重载函数前加 explicit关键字可以限制该函数禁止使用隐式类型转换(C++ 11)

(但可以强制类型转换)

explicit operator int();

  • 问题背景

class T
{
public:
    T(int val)
    {}

    operator int(){
        return 1;
    }

    int operator+(T x){
        return 2;
    }
};

int main()
{
    T t1{ 100 }, t2{ 200 };
    int x = t1 + 100;//报错
    //有歧义,t1可以隐式类型转换为int,x=101
    //也可以是100类型转换为T,x=102
}
  • 使用explicit

class T
{
public:
    T(int val)
    {}

    explicit operator int()//explicit
	{
        return 1;
    }

    int operator+(T x){
        return 2;
    }
};

int main()
{
    T t1{ 100 }, t2{ 200 };
    int x = t1 + 100;
    //不允许t1隐式类型转换成int,所以100转换成T类
    std::cout<<x;//2

    int y=(int)t1+100;//可以强制类型转换
    std::cout<<t1;//1
}
explicit operator int()
{...}


hstring str{-123};

int x=str+123;//报错
//因为 str+123 是hstring类型的,而operator int()被explicit修饰,即hstring不能隐式类型转换为int

int x=(int)(str+123);//可以强制类型转换
std::cout<<x;//-123123

int x=(int)(str)+123;//-123+123=0
std::cout<<x;//0

bool类型与void*的选择

某些时候,我们为了表示某个类里的指针是否为空,可以重载该类的void*类型来实现如下操作

if(p)

if(!p)

if(p!=NULL)

if(p!=nullptr)

但是其实也可以实现重载bool类型转换来实现该操作,但是我们一般不推荐重载bool类型

hstring::operator void* ()
{
	return cstr;
}

int main()
{
	hstring str{ 123 };
	if (str == nullptr)std::cout << "空字符串";
	else std::cout << "非空字符串";
}

重载内存分配释放

new和delete的工作原理

new的工作原理

Role*user=new Role();

  1. 通过new分配内存空间 (能接管)

  1. 调用构造函数

  1. 返回指针

delete user;

  1. 调用析构函数

  1. 通过delete释放内存 (能接管)

重载内存分配

内存分配在C++中是比较重要的内容,有的时候我们需要重载内存分配和释放,大部分时候是为了解决内存碎片的问题,

  • new的六种形式

//new的六种形式:
void* operator new (size_t size);//size_t就是unsigned,size代表你要分配的内存的大小
void* operator new[](size_t size);
void* operator new(size_t size,const std:nothrow_t&) noexcept;
void* operator new[](size_t size,const std:nothrow_t&) noexcept;
//禁止重载的两种形式
void* operator new(size__t size,void* p) noexcept;//可以指定内存分配到这块区域
void* operator new[](size_t size,void* p) noexcept;

blut shota = new ((void*)0x20000) bult[10];

char* mem=new char[0x1000];

int main()
{
    blut* shota = new (mem) blut[10];

	std::cout<<(void*)mem<<std::endl;//0175A578
    std::cout<<shota<<std::endl;//0175A578

    delete[] (mem);
}
void* blut::operator new(size_t size)
{
    return new blut;//死循环,因为new blut继续调用void* operator new(size_t size)
}
——————————————————————————————————————————————————————————————————————————————————————————
void* blut::operator new(size_t size)
{
    return ::operator new (size);//加上全局符号,调用的是默认的那个new
}

重载内存释放

内存分配在C++中是比较重要的内容,有的时候我们需要重载内存分配和释放,大部分时候是为了解决内存碎片的问题,

delete的六种形式:

void operator delete (void* adr) noexcept;
void operator delete[](void* adr) noexcept;
void operator delete(void* adr,const std:nothrow_t&) noexcept;
void operator delete[](void* adr,const std:nothrow_t&)noexcept;
void operator delete(void* adr,void* p) noexcept;
void operator delete[](void+ adr,void* p) noexcept;
class blut
{
public:
    float x;
    float h;
    float y;
    float damage;

    void* operator new(size_t size);
    void operator delete(void* adr) noexcept;
};

/*
void* blut::operator new(size_t size)
{
    return new blut;//死循环
}
*/

char* mem = new char[0x10000];

void* blut::operator new(size_t size)
{
    return mem;
}

void blut::operator delete(void* adr) noexcept
{

}


int main()
{
    blut* shota = new blut;

    shota->x = 100;

    delete shota;
}

小细节

  1. void* blut::operator new(size_t size)其实是static类型,所以没有this指针

因为new的时候还在分配内存空间,没有自己的内存空间也就没有this指针

  1. void blut::operator delete(void* adr) noexcept也是static类型,也没有this指针

因为在使用delete之前已经调用析构函数,内存空间已经释放

删除不想用的new和delete版本

删除系统默认函数

class blut
{
public:
    float x;
    float h;
    float y;
    float damage;

    void* operator new(size_t size);
    void operator delete(void* adr) noexcept;

    void* operator new[](size_t size) = delete;//删除
    void operator delete[](void* adr) = delete;//删除
};

重载带有额外参数的new和delete

为了方便和提高灵活性,可以重载带有额外参数的new和delete版本

void* operator new(size_t size.const char* meminfo);
void*operator delete(void*adr,const char* meminfo) noexcept;

但是带有额外参数的delete版本不能手动调用, 只有在构造函数发生异常的时候, 系统会自动调用

void* blut::operator new(size_t size,const char* txt)
{
    std::cout << txt;
    return mem;
}
//要写相对应的delete版本
void blut::operator delete(void* adr, const char* txt) noexcept
{

}

int main()
{
    blut* shota = new ("test") blut;

    delete () shota;//报错,所以还要准备一个普通版本的delete
}
————————————————————————————————————————————————————————————————————————————————————————
void* blut::operator new(size_t size,const char* txt)
{...}
void blut::operator delete(void* adr, const char* txt) noexcept
{...}

void blut::operator delete(void* adr) noexcept//普通版本的delete
{...}

int main()
{
    blut* shota = new ("test") blut;
    delete shota;
}
class blut
{
    bool bUse = true;
public:
    float x;
    float h;
    float y;
    float damage;

    ~blut();
    void* operator new(size_t size,const char* txt);
    void operator delete(void* adr, const char* txt) noexcept;
    void operator delete(void* adr) noexcept;
    void* operator new[](size_t size) = delete;
    void operator delete[](void* adr) = delete;
};


char* mem = new char[1000 * sizeof(blut)]{};//记得将内存初始化为0

void* blut::operator new(size_t size,const char* txt)
{
    blut* dat = (blut*)mem;
    for (int i = 0; i < 1000; i++)
    {
        if (!dat[i].bUse)return &dat[i];
    }
}

void blut::operator delete(void* adr, const char* txt) noexcept
{

}

void blut::operator delete(void* adr) noexcept
{
    //static类型的函数,不能将bUse设置成false
    //在析构函数里设置
    //delete函数的工作原理:先调用析构函数,然后使用delete释放内存
}

blut::~blut()
{
    bUse = false;
}


int main()
{
    blut* shota1 = new ("test") blut;
    blut* shota2 = new ("test") blut;
    blut* shota3 = new ("test") blut;
    delete shota1;
    blut* shota4 = new ("test") blut;//放在shota1的内存里
    delete shota2;
    blut* shota5 = new ("test") blut;//放在shota2的内存里

    std::cout << shota1 << std::endl;//010AECA0
    std::cout << shota2 << std::endl;//010AECB4
    std::cout << shota3 << std::endl;//010AECC8
    std::cout << shota4 << std::endl;//010AECA0
    std::cout << shota5 << std::endl;//010AECB4
}

重置递增递减运算符

重载前置++/--

前置++/--可以重载为类的方法或者是全局函数

方法:

返回类型 operator++();

返回类型 operator--();

全局函数

返回类型 operator++(操作数类型 操作数);

返回类型 operator--(操作数类型 操作数)

class hint
{
	char* mem[4];
public:
	hint(int val=0);
	~hint();
	operator int();
	void operator=(int val);
	hint& operator++();//前置++  (类的方法)

};
hint& operator--(hint& val);//前置--  (全局函数)

hint& hint::operator++()//前置++,先+1后进行运算 
{
	*this = *this + 1;
	return *this;
}

hint& operator--(hint& val)//前置--(全局函数)
{
	val = val - 1;
	return val;
}

后置+/--

后置++/--可以重载为类的方法或者是全局函数

方法:

返回类型 operator++(int); //int参数没有意义,就是用来区分前置++和后置++

返回类型 operator--(int);

全局函数

返回类型 operator++(操作数类型 操作数, int);

返回类型 operator--(操作数类型 操作数, int);

hint& hint::operator++(int)
{
	hint val = *this;

	*this = *this + 1;
	return val;
}
/*使用时报错
因为hint val=*this;会调用编译器默认的构造函数hint(hint& val);
于是构造函数进行纯粹的复制
	mem[0] = new char;
	mem[1] = new char;
	mem[2] = new char;
	mem[3] = new char;
而函数结束时val调用析构函数
hint::~hint()
{
	delete mem[0];
	delete mem[1];
	delete mem[2];
	delete mem[3];
}
指针被释放,再使用时就会报错
*/
————————————————————————————————————————————————————————————————————————————————————————
hint& hint::operator++(int)
{
	hint val = (this)*this;//调用hint (int val)构造函数
	*this = *this + 1;
	return val;
}

/*仍然出错
比如说a++
return val的之后a=val,会调用hint (hint& val),同样直接复制地址
而函数删除的时候调用析构函数,同上,内存被释放
a使用的时候就会报错
*/
————————————————————————————————————————————————————————————————————————————————————————
//解决方法:自己写一个hint (hint& val)
hint::hint(hint& val) :hint((int)val)
//委托hint(int val)构造,需要将该构造函数hint类型的val转换成int类型
{}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值