1.P24 枚举
参考: 视频
1.1.枚举类型的本质
- 枚举类型的本质就是int整数,只不过通过枚举类型限制了整数的取值范围只能在枚举所列出来的范围内。因为是整数,所以枚举类型可以进行大小的比较
- 可以制定枚举类型中的数据类型,比如可以指定为
unsigned char
节约内存(不过意义不大)。但是无论怎么设定类型,都只能是整数,不能是float
double
小数。
enum Level : unsigned char // 设定内部的数据都是unsigned char 型
{
Error, Warn, Info
};
1.2.在类中声明枚举类型
以之前写的Log类为例,其中Log的级别就很适合用enum类型定义,代码如下所示。
注意:枚举类型不能作为命名空间,所以尽管在类中定义了enum Level
,但是其内部的枚举类型是直接属于Log类的。也就相当于在归属关系上enum Level
像是不存在一样,其内部的枚举类型就像类的成员变量一样,因此枚举类型的名字要注意避免和类的成员变量、成员函数重复。这么来看,enum Level
相当于只是把枚举类型进行了一下结构上的组织,但是并没有其他作用。
#include <iostream>
class Log
{
// 注意这里public可以写好几块,这样把变量和函数分开写更清晰
public:
enum Level
{
// 注意下面这些类型还是属于Log类的,因为枚举Level并不能算作一个命名空间
// 因此这里的变量命令需要注意别和成员函数Error Warn Info重复,因为他们都是属于Log类的
level_error = 0, level_warn, level_info
};
private:
// 因为Level中的类型直接属于Log类,所以这里直接写level_info即可,没有Level前缀(枚举不能作为命名空间)
Level log_level_ = level_info;
public:
void SetLevel(Level level)
{
log_level_ = level;
}
void Error(const char* msg)
{
// 注意这里的判断逻辑,log对象的级别数字越大,那么输出信息越能包含级别数字小的
if(log_level_ >= level_error)
{
std::cout << "[ERROR]: " << msg << std::endl;
}
}
void Warn(const char* msg)
{
if(log_level_ >= level_warn)
{
std::cout << "[WARN]: " << msg << std::endl;
}
}
void Info(const char* msg)
{
if(log_level_ >= level_Info)
{
std::cout << "[INFO]: " << msg << std::endl;
}
}
};
int main()
{
Log log;
// 注意枚举的类型是直接属于Log类的
log.SetLevel(Log::level_info);
log.Error("hello"); // 可以输出
log.Warn("hello"); // 可以输出
log.Info("hello"); // 不会输出
return 0;
}
2.P25 构造函数
2.1.类成员变量的初始化
-
如果类成员变量没有进行初始化,那么在C++中它将保存内存中原有的值,而在java中会对int float等一些基本数据类型的成员变量自动赋初值为0。
-
如果没有赋初值的话,可能在类外访问这些变量的时候编译器也会报错。
2.2.删除默认构造函数(禁止实例化对象)
有的时候只想让外部使用类的静态成员函数,而不像实例化这个类的对象。此时有两种办法:
- 设置private来隐藏默认构造函数,编译会得到错误,因为不能访问构造函数。不设置private编译会通过,说明C++为我们提供了一个默认构造函数。
- 删除默认构造函数,简单地写
Log()=delete;
。我们就不能实例化Log类的对象,因为默认构造函数已经被删除。
3.P26 析构函数
- 构造函数是在我们创建一个新的实例对象时运行,而析构函数则是在销毁对象时运行。任何时候一个对象要被销毁时,析构函数将被调用。构造函数通常是设置变量或者做任何需要的初始化,析构函数是卸载变量等东西,并清理使用过的内存,析构函数同时适用于栈和堆分配的对象。
- 比如使用new分配一个对象,当我们调用delete时,析构函数会被调用。而如果只是一个栈对象,当作用域结束,栈对象将被删除,此时析构函数也会被调用。
- 构造函数和析构函数在声明与定义时的唯一区别,就是放在析构函数前面的波浪号。
- 析构函数的本质是一个特殊函数或特殊方法,在对象被销毁时调用。如果我们在构造函数中调用了特定的初始化代码,而不使用析构函数销毁这些东西,就可能会造成内存泄露。
#include<iostream>
class Entity
{
public:
float X, Y;
Entity()
{
X = 0.0f;
Y = 0.0f;
std::cout << "Created Entity" << std::endl;
}
~Entity()
{
std::cout <<"Destroyed Entity" << std::endl;
}
void Print()
{
std::cout << X<<","<< Y << std::endl;
}
};
void Function()
{
Entity e;
e.Print();
}
int main()
{
Function();
std::cin.get();
}