c++ 成员初始化列表 & 三元运算符 & new & delete & explict & 运算符重载

2023-03-06

结论:类中的初始化最好都使用成员初始化列表

成员初始化列表

成员初始化列表是一个很好用的东西,用在类的初始化函数当中

class Entity {
public:
	int a;
	int b;
	int c;
	Entity() 
		: a(1),b(2),c(3) //成员初始化列表
	{
		std::cout << a << b << c << std::endl;
	}
};
int main() {
	Entity test;
}

在一个类需要初始化很多变量时,你可以直接一行解决,十分方便。

为什么要使用成员初始化列表

#include <iostream>
#include <string>

class example {
public:
	example() {
		std::cout << "example created!" << std::endl;
	}
	example(int x) {
		std::cout << "example created with " << x << std::endl;
	}
};

class Entity {
public:
	example e;
	std::string m_string;
	int a;
	int b;
	int c;
	Entity() 
		: a(1),b(2),c(3)
	{
		e = example(8);
		m_string = "hahah";
		std::cout << a << b << c << std::endl;
	}
};
int main() {
	Entity test;

}

运行这段代码,我们发现 Entity类型中的example被初始化了2次(运行后发现打印了2输出函数)
而使用成员初始化列表则不会出现这种情况。

#include <iostream>
#include <string>

class example {
public:
	example() {
		std::cout << "example created!" << std::endl;
	}
	example(int x) {
		std::cout << "example created with " << x << std::endl;
	}
};

class Entity {
public:
	example e;
	std::string m_string;
	int a;
	int b;
	int c;
	Entity() 
		: a(1),b(2),c(3),e(8),m_string("hhh")
	{
		std::cout << a << b << c << std::endl;
	}
};
int main() {
	Entity test;
}

三元运算符

int a = 10;
int b = a > 10 ? 5 : 6;

就是一种三元运算符的使用方式,等价替换为:

int a = 10;
if(a>10){
	b = 5;
}else{
	b = 6;
}

用三元运算符可以减少代码行数,简化代码,但是尽量不要用三元运算符进行嵌套(固然代码很少,但是很搞人心态哈哈哈)

new/delete

newdelete是c++中的用于在heap上申请内存空间和释放空间的关键字。

直接上例子

#include <iostream>
#include <string>
int main() {
	int* a = new int(5);
	std::cout << *a << std::endl;
	delete a;
	int* b = new int[50];
	delete[] b;
}

delete[]用于当你申请的是一个数组时。

new/delete实际上做了什么

new实际上调用了malloc函数,然后再调用类的构造函数。
delete实际上调用了类的析构函数,然后调用了free函数

explict关键字

直接先来看代码

#include <iostream>
#include <string>

class Entity {
public:
	std::string m_name;
	int m_age;
	Entity(const std::string &name)
		:m_name(name),m_age(-1) {
	}
	Entity(int age)
		:m_name("unknown"), m_age(age) {
	}
};

void print_entity(Entity& entity) {
	std::cout << entity.m_name << std::endl;
}
int main() {
	Entity a = 22;//?神马东西
	print_entity(a);
}

其实咱们可以发现,它还是能正常运行的。原因在于c++编译器自动对其做了隐式转换(implict convert
然后还有个问题

#include <iostream>
#include <string>

class Entity {
public:
	std::string m_name;
	int m_age;
	Entity(const std::string &name)
		:m_name(name),m_age(-1) {
	}
	Entity(int age)
		:m_name("unknown"), m_age(age) {
	}
};

void print_entity(Entity& entity) {
	std::cout << entity.m_name << std::endl;
}
int main() {
	Entity a = 22;
	print_entity(a);
	Entity b = "wsxk";//无法通过编译
	print_entity(b);
}

implict convert只能隐式转换一次,”wsxk”是一个const char *类型,需要转变为std::string类型,然后再转变为Entity类型,其中隐式转换了2次,这是编译器不允许的.

如何避免意外的隐式转换

利用explict关键字

#include <iostream>
#include <string>

class Entity {
public:
	std::string m_name;
	int m_age;
	explicit Entity(const std::string &name)
		:m_name(name),m_age(-1) {
	}
	explicit Entity(int age)
		:m_name("unknown"), m_age(age) {
	}
};

void print_entity(Entity& entity) {
	std::cout << entity.m_name << std::endl;
}
int main() {
	Entity a = 22; //报错
	print_entity(a);
	Entity b = "wsxk";//报错
	print_entity(b);
}

operator

c++允许我们重新定义类中的一些运算符,例如+,-,*,/,==,!=的行为,从而使得编写代码时变得简洁

#include <iostream>

class Vector {
public:
	float x, y;
	Vector(float a, float b):x(a),y(b) {}

	Vector Add(const Vector& other) const {
		return Vector(x + other.x, y + other.y);
	}
	Vector operator+(const Vector& ohter)const {
		return Add(ohter);
	}
	Vector Multiply(const Vector& other) const {
		return Vector(x * other.x, y * other.y);
	}
	Vector operator*(const Vector& other)const {
		return Multiply(other);
	}
	bool equal(const Vector& other)const {
		return x == other.x && y == other.y;
	}
	bool operator==(const Vector& other) const {
		return equal(other);
	}
};

int main() {
	Vector position(1.0f, 2.0f);
	Vector speed(1.1f, 1.1f);
	Vector powerup(1.2f, 1.2f);
	Vector result = position+speed*powerup;
	std::cout << result.x << " " << result.y << std::endl;
	if (position == speed) {
		std::cout << "attack" << std::endl;
	}
	else {
		std::cout << "miss" << std::endl;
	}
}

值得注意的是,不应该重载过多的operator

this关键字

this关键字是类内部用于指向自身的指针

#include <iostream>

class Entity {
public:
	int x, y;
	Entity(int x, int y) {
		this->x = x;
		this->y = y;
	}
};

int main() {
	Entity a(3, 4);
	std::cout << a.x << " " << a.y << std::endl;
}

可以方便的解决参数和变量重名的问题