C++ 可见性、class的基本使用、enum、成员初始化列表

1 可见性

可见性对性能没有任何影响,也不会产生不同的代码。只是人为规定,用于提示,可以类比类型的定义。

基类友元子类外部
public
protected
private

可见性的意义:
允许或不允许自己或其他人访问类中的特定成员。将不想被直接访问的成员定义为private,保证代码的正常运行。

小例子:
一个摇杆控制方向的UI界面。该类定义如下:

class UI
{
private:
    int x;
    int y;
public:
    void refresh(int direction)
    {
        // 用于刷新显示界面,控制摇杆移动方向
    }
    void move(int direction){
        // 判断哪个方向移动多少,改变xy坐标值
        // 并刷新显示,产生摇杆往对应方向移动的显示
        refresh(direction);
    }
};

如果直接修改xy的值,摇杆移动的画面时无法显示的。

2 class和struct的区别

本质区别:在不声明是public还是private的情况下,class默认是private,而struct默认是public。除此以外,本质上🈚️区别了。
一般情况下,struct用来维护数据,class用于更复杂的功能,如继承等。另外一个角度来看,用class来实例对象(产生个体)。

3 class小例子

不同的成员可以分开写,即使他们的可见性是相同的
例如将公共的数据和函数分别写在两个public中,这样比较好维护
这个小例子是一个关于日志输出的类:

class Log
{
public:
    const int LogLevelError = 0;
    const int LogLevelWarning = 1;
    const int LogLevelInfo = 2;
private:
    int m_LogLevel = LogLevelInfo;
public:
    void SetLevel(int level)
    {
        m_LogLevel = level;
    }
    
    void Error(const char* message)
    {
        if (m_LogLevel>=LogLevelError)
            cout << "[ERROR]:" << message << endl;
    }
    
    void Warn(const char* message)
    {
        if (m_LogLevel>=LogLevelWarning)
            cout << "[WARNING]:" << message << endl;
    }
    
    void Info(const char* message)
    {
        if (m_LogLevel>=LogLevelInfo)
            cout << "[INFO]:" << message << endl;
    }
};


int main(){
    Log log;
    log.SetLevel(log.LogLevelWarning);
    log.Warn("Hello");
    log.Error("Hello");
    log.Info("Hello");
    // 输出有WARNING和ERROR
}

4 enum

枚举其实是一个人为添加的限制,尤其适用于不同状态要有对应操作的情况下,比如上述的Log。
要定义所有代表状态的变量并完成赋值,使用枚举可以将这些状态变量集中在一起定义,并且自动赋值(可以自己给任意变量赋值,如果不赋值,则默认第一个变量为0,其他变量值为前一个变量值+1),增加代码可读性。另外,也可以防止其他部分代码修改表示状态的变量值

这里需要强调:
所有枚举变量值都是整数,但这不代表变量一定是int类型,这里回忆之前类型章节所述。由于枚举变量都是整数,因此可以将枚举变量定义成可以接受整数的类型,如char等,这意味着float、double是不行的。由于不同类型变量占用的空间不同,根据状态个数选择合适类型可以节省空间。

将上述Log用枚举实现:

class Log
{
public:
    enum Level : char
    {
        // 命名需要注意,变量不要和函数重名,
        // 所以这里都加上了Level作为前缀来区分变量
        LevelError = 0, LevelWarning, LevelInfo
    };
private:
    int m_LogLevel = LevelInfo;
public:
    void SetLevel(int level)
    {
        m_LogLevel = level;
    }
    
    void Error(const char* message)
    {
        if (m_LogLevel>=LevelError)
            cout << "[ERROR]:" << message << endl;
    }
    
    void Warn(const char* message)
    {
        if (m_LogLevel>=LevelWarning)
            cout << "[WARNING]:" << message << endl;
    }
    
    void Info(const char* message)
    {
        if (m_LogLevel>=LevelInfo)
            cout << "[INFO]:" << message << endl;
    }
};


int main(){
    Log log;
    log.SetLevel(Log::LevelWarning);
    log.Warn("Hello");
    log.Error("Hello");
    log.Info("Hello");
    // 输出有WARNING和ERROR
}
	

5 构造函数

负责类的初始化,与类同名,可重载

class Entity
{
public:
    float X,Y;
	// 构造1
    Entity(){
        X = 0;
        Y = 0;
    }
    // 构造2
    Entity(float x, float y)
    {
        X = x;
        Y = y;
    }
    void Print(){
        cout << X << ',' << Y << endl;
    }
};

int main(){
	// 不同构造方式
    Entity a;
    Entity b(1,1);
    a.Print();
    b.Print();
    // 输出0,0和1,1
}

工具类:如果一个类只有一些静态函数,我们不希望使用者实例化这个类的对象,而是直接使用这个类中的方法,这就需要对构造函数进行操作:
方式1:构造函数私有化
方式2:删除构造函数(推荐)

// 方式1
class Log
{
private:
    Log(){}
public:
    static void Write(){
        // 巴拉巴拉
    }
};

// 方式2
class Log
{
public:
	Log() = delete;
    static void Write(){
        // 巴拉巴拉
    }
};

5.1 成员初始化列表

在使用构造函数初始化类成员变量时,成员初始化列表是更好的方式。需要注意的是列表顺序必须和类成员变量声明顺序一致

class Entity
{
public:
    string m_Name;
    int m_Score;
public:
	// 使用成员初始化列表
    Entity()
        : m_Name("Unknow"), m_Score(0) // 冒号后面接列表
    {
        // balabala
        cout<< m_Name << endl;
        cout<< m_Score << endl;
    }
    // 优于不使用成员初始化列表
//    Entity()
//    {
//        m_Name = "Unknow";
//        m_Score = 0;
//        cout<< m_Name << endl;
//        cout<< m_Score << endl;
//    }
};

这样代码很简洁,可以把变量赋值和其他功能分开。而且有利于提升性能:

class Example
{
public:
    Example()
    {
        cout<< "Created Entity" << endl;
    }
    Example(int x)
    {
        cout<< "Created Entity with "<< x<< "!"<< endl;
    }
};

class Entity
{
public:

    Example m_Example;
public:
	// 成员初始化列表的方法
	// 输出只有Created Entity with 8!
    Entity()
        : m_Example(Example(8))	//写成m_Example(8)也可以
    {
    }
	// 不使用的话,输出为Created Entity和Created Entity with 8!
//    Entity()
//    {
//        m_Example = Example(8);
//    }
};

这里可以看到,不使用成员初始化列表的话,Example会被创建两次,相当于先用无参数构造对象,然后又用有参数构造对象并替换了之前无参数的对象,影响性能。不使用的代码等价于如下:

class Entity
{
public:
    Entity()
    {
    	// 构造两次
        Example m_Example;
        m_Example = Example(8);
    }
};

6 析构函数

清理使用的内存,销毁(delete)或作用域结束(如函数中创建对象)时使用。比如动态申请空间后(new),需要在析构函数中释放该空间,否则这些内存空间将被一直占用,直到程序结束。动态申请的这些空间都在堆中,需要开发者自行释放。

class Entity
{
public:
    
    Entity(){
        cout<<"Create Entity"<< endl;
    }
    // ↓就是这玩意
    ~Entity(){
        cout<<"Destory Entity"<< endl;
    }
};

int main(){
    Entity e;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值