Cherno C++【41-45】

【41】运算符及其重载

运算符时我们使用给的一种符号,通常代替一个函数来执行一些事情。比如加减乘除、dereference运算符、箭头运算符、+=运算符、&运算符、左移运算符、new和delete、逗号、圆括号、方括号等等等等。

重载这个术语本质上是给运算符重载赋予新的含义,或者添加参数,或者创建,允许在程序中定义或更改运算符的行为。
运算符就是函数。运算符重载是一个非常有用的特性,但在Java等语言中不受支持,它在C#等语言中得到部分支持,C++给了我们完全的控制权。

不用运算符实现加、乘

struct Vector2  //向量结构体
{
	float x, y;

	Vector2(float x, float y)
		: x(x),y(y) {}

	Vector2 Add(const Vector2& other) const
	{
		return Vector2(x + other.x, y + other.y);
	}
	Vector2 Multiply(const Vector2& other) const
	{
		return Vector2(x * other.x, y * other.y);
	}
};
int main() 
{
	Vector2 position(4.0f, 4.0f);
	Vector2 speed(0.5f, 1.5f);
	Vector2 powerup(1.1f, 1.1f);
	
	Vector2 result1 = position.Add(speed.Multiply(powerup)); //position+(speed*powerup),Java中只能这么用

	Vector2 result2 = position.+ speed * powerup;  //用运算符定义,运算符同样存在优先级

	std::cin.get();

加入运算符后

Vector2 operator+(const Vector2& other)const
	{
		return Add(other);
	}
int main() 
{
	Vector2 position(4.0f, 4.0f);
	Vector2 speed(0.5f, 1.5f);
	Vector2 powerup(1.1f, 1.1f);
	
	Vector2 result1 = position.Add(speed.Multiply(powerup)); //position+(speed*powerup),Java中只能这么用

	Vector2 result2 = position.+ speed * powerup;  //用运算符定义,运算符同样存在优先级

	std::cin.get();

左移运算符

std::ostream& operator<<(std::ostream& stream, const Vector2& other)  // 重载左移运算符
{
	stream << other.x << "," << other.y;
	return stream;
}

std::cout << result2 << std::endl;

【42】this关键字

通过this可以访问成员函数,成员函数是一个属于某个类的函数或者方法,在方法内部可以引用this。
this是一个指向当前对象实例的指针,该方法属于这个对象实例。
链接:link

【43】对象生存期

内存以及对象是如何在栈上生存的,生存期对于基于栈的变量意味着什么。
每当我们在c++中进入一个作用域,我们是在push栈帧,它不一定非得是将数据push进一个栈帧。
栈上变量自动销毁,在很多方面都很有用,可以帮助我们自动化代码。比如类的作用域,比如智能指针unique_ptr,这是一个作用域指针,或者像作用域(scoped_lock)。

但最简单的例子可能是作用域指针,他基本上是一个类,它是一个指针的包装器,在构造时用堆分配指针,然后在析构时删除指针,所以我们可以自动化这个new和delete。

【44】智能指针

智能指针本质上是原始指针的包装。当你创建一个智能指针,它会调用new并为你分配内存,然后基于你使用的智能指针,这些内存会在某一时刻自动释放。

unique_ptr

他的构造函数时explicit,所以需要显式调用构造函数。作用域结束,Entity就会被自动摧毁。
unique_ptr 指针不能被复制,,因为只要作用域结束了,在堆上分配的内存也会被释放掉,因此在该指针在实现上强制地将拷贝构造函数和拷贝构造符都删除,避免错误的行为。
但是为了异常安全,一般我们使用std::make_unique

#include <memory>

class Entity
{
public:
	
	Entity()
	{
		std::cout << "created" << std::endl;
	}

	~Entity()
	{
		std::cout << "destoryed" << std::endl;
	}

	void Print() {}
};

int main() 
{
	{
		std::unique_ptr<Entity>  entity(new Entity());  

		//std::unique_ptr<Entity>  entity = std::make_unique<Entity>();    //为了异常安全,一般我们使用std::make_unique

		entity->Print();
	}

	std::cin.get();

}

share_ptr

和 unique_ptr 由于异常安全的原因而不推荐使用 new 的方式创建智能指针不同,因为 shared_ptr 需要分配另一块内存,称为控制块,用来存储引用计数,所以如果使用 new 的形式来创建一个对象再将其传给 shared_ptr 的构造函数,他就必须做两次内存分配。所以需要用make_share将他们组合在一起,这样更有效率。
share_ptr是可以复制的

	std::shared_ptr<Entity> shareEntity = std::make_shared<Entity>();
	std::shared_ptr<Entity> e0 = shareEntity;  //share_ptr可以复制

weak_ptr

和复制 shared_ptr 所做的一样,但当你把 shared_ptr 赋值给一个 weak_ptr,假如唯一的那个 shared_ptr 指针死去,内存就会被删除,因为赋值给 weak_ptr 并不会增加引用数量。例如你在排序一个集合,你不需要关注指针是否有效,你只需要存储一个他们的引用就好了。

std::weak_ptr<Entity> entity = std::make_weak<Entity>();

智能指针选择顺序

优先选择unique_ptr ,因为有一个较低的开销,如果需要分享,则选择share_ptr。

【45】复制与copy构造函数

复制普通变量与复制指针是不同的。
在栈中创建地对象,其数值存储在不同地内存地址,当赋值发生时,就是将值准确地拷贝到对方地内存那里。但在堆中创建的对象,我们所持有的变量是一个指针,这个指针存储着内存地址,并指向堆中的内存,当我们进行赋值时,实际上改变的是地址,也就是两个变量都将指向同一块内存了。

struct Vector2
{
	float x, y;
};

int main() 
{
	Vector2* a = new Vector2(); //在堆上创建指针
	Vector2* b = a; // a,b指向相同的内存地址
	b++; //只改变b,a指针是完整的
	b->x = 2; //访问内存地址,设置为某个值,同时影响a,b


	std::cin.get();

复制字符串

class String
{
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string)
	{
		m_Size = strlen(string);
		m_Buffer = new char[m_Size+1]; //数组大小要+1,留给止位符
		memcpy(m_Buffer, string, m_Size); //复制函数memcpy[destination,source,size]
	}

	~String()
		{
			delete[] m_Buffer ;
		}
		
	//友元函数,声明一个友元函数
	friend std::ostream& operator<<(std::ostream& stream, const String& string);

};

//打印字符串的函数,重载左移操作符
std::ostream& operator<<(std::ostream& stream, const String& string)
{
	stream << string.m_Buffer();
	return stream;
}
int main() 
{
	String string = "cherno";
	std::cout << string << std::endl;

	std::cin.get();

}

浅拷贝:复制的是地址。如果其中一个调用了析构函数并且删除了堆上内存,当另一个在调用析构函数试图删除内存时,就会抛出异常,因为同一块内存不能被销毁两次。
浅拷贝是新增了一个指针指向内存,深拷贝是复制内存。

String string = "cherno";
String second = string; //浅拷贝,复制的是地址,即string和second指向同一段内存

深拷贝
想要实现深拷贝,希望被赋值的变量拥有自己的唯一的内存块,有自己的指针,就需要使用到拷贝构造函数,该构造函数会在你赋值复制时调用。

	//c++默认提供的拷贝构造函数
	//执行深copy必须使用的代码
	String(const String& other)
		:m_Size(other.m_Size)
	{
		m_Buffer = new char[m_Size + 1];
		memcpy(m_Buffer, other.m_Buffer, m_Size + 1); //从other对象复制

	}

建议总是通过const & 去传递对象!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cherno C. 是指切爾諾河,它是位於烏克蘭的一條河流。切爾諾河全長331公里,流域面積約15,000平方公里。它發源於烏克蘭西部的庫茲涅佐夫斯基區,並且在基輔東北方注入第聶伯河。 切爾諾河在烏克蘭的歷史和文化中具有重要的地位。在中世紀時,切爾諾河流域是一個重要的商業和交通中心,有許多城市和貿易聚居地沿岸建立。例如,烏克蘭西北部大葉支流的古城切爾諾希夫(今日的切爾諾夫策)就位於切爾諾河畔。切爾諾河的交通功能在經濟和文化上對於當地居民有著極大的影響。 然而,切爾諾河的名字也伴隨著一個嚴重的災難,即切爾諾貝利核事故。1986年4月26日,切爾諾貝利核電廠發生了爆炸,導致大量的核輻射釋放到環境中。切爾諾河成為了輻射污染的來源之一,對該地區的生態環境和人民的健康產生了長期的不良影響。 然而,多年來,烏克蘭政府和國際社會通過各種措施和項目努力解決切爾諾貝利核事故的後果,包括對受影響地區進行清理和重建工作,以及提供醫療和援助。此外,切爾諾河流域的自然環境也逐漸復原,許多野生動植物重新回歸。 總而言之,切爾諾河對於烏克蘭的重要性無可否認,它在經濟、文化和環境等方面都扮演著重要的角色。儘管面對災難,人們正在努力修復和保護這條河流,以為社會和環境的發展做出貢獻。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值