C++面向对象编程之三:初始化列表、类对象作为类成员、静态成员

本文介绍了C++中的初始化列表用于成员属性初始化,并通过示例展示了如何使用无参和有参构造函数。文章还探讨了类对象作为类成员时的构造顺序,即先构造对象成员,后构造类本身,析构时顺序相反。另外,文章讨论了静态成员,包括静态成员变量和静态成员函数,强调它们的共享特性及访问规则。
摘要由CSDN通过智能技术生成
初始化列表

C++提供了初始化列表语法,可以用于成员属性初始化。

语法规则:

无参构造函数():属性1(值1), 属性2(值2), ...
{
}

有参构造函数(形参1, 形参2, ...):属性1(形参1), 属性2(形参2), ...
{
}

example:写一个怪物类,有怪物id和血量属性,并用初始化列表的形式初始化成员属性

#include <iostream>
using namespace std;

class Monster
{
    public:
    Monster():m_monsterId(10001), m_blood(1000)
    {

    }

    Monster(const int monsterId, const int blood):m_monsterId(monsterId), m_blood(blood)
    {

    }

    void print_monster_info()
    {
        cout << "怪物id = " << m_monsterId << ",血量 = " << m_blood << endl;
    }

    private:
    int m_monsterId; //怪物id
    int m_blood; //血量
};

int main(int argc, char *argv[])
{
    Monster m1;
    m1.print_monster_info();

    Monster m2(10002, 2000);
    m2.print_monster_info();

    return 0;
}
类对象作为类成员

C++中的另一个类的对象可以作为类的成员,我们称为该成员为对象成员。那么这时是先构造对象成员,还是先构造该类呢?答案是先构造对象成员后构造该类,析构函数刚好相反,先析构该类后析构对象成员

example:举一个有趣的例子,有一个技能类,一个怪物类,这时怪物会有技能了,所以在设计怪物类时,会有技能类作为怪物类的成员。用来验证另一个类的对象作为类成员时,先构造对象成员,后构造该类。析构则先析构该类,后析构对象成员。

#include <iostream>
using namespace std;

enum SKILL_TYPE
{
    SUB_DEST_BLOOD_ADD_SELF_BLOOD = 0
};

int g_line = 0;

class Monster;

class Skill
{
    public:
    Skill():m_skillType(SUB_DEST_BLOOD_ADD_SELF_BLOOD), m_val(500)
    {
        g_line++;
        cout << g_line << "行:Skill()无参构造函数被调用" << endl;
    }
    Skill(const int skillType, const int val):m_skillType(skillType), m_val(val)
    {
        g_line++;
        cout << g_line << "行:Skill(const int skillType, const int val)有参构造函数被调用" << endl;
    }
    Skill(const Skill &s)
    {
        m_skillType = s.m_skillType;
        m_val = s.m_val;
        
        g_line++;
        cout << g_line << "行:Skill(const Skill &s)拷贝构造函数被调用" << endl;
    }

    ~Skill()
    {
        g_line++;
        cout << g_line << "行:~Skill()析构函数被调用" << endl;
    }

    //施法
    void spell(Monster &src, Monster &dest);

    private:
    int m_skillType; //技能类型
    int m_val;
};

class Monster
{
    public:
    Monster():m_monsterId(10001), m_name("怪物"), m_blood(1000), m_skill()
    {
        g_line++;
        cout << g_line << "行:Monster()无参构造函数被调用" << endl;
    }
    Monster(const int monsterId, const string name, const int blood, const int skillType, const int skillVal):
    m_monsterId(monsterId), m_name(name), m_blood(blood), m_skill(skillType, skillVal)
    {
        g_line++;
        cout << g_line << "行:Monster(const int monsterId, const string name, const int blood, const int skillType, const int skillVal)有参构造函数被调用" << endl;
    }
    Monster(const Monster &m)
    {
        m_monsterId = m.m_monsterId;
        m_name = m.m_name;
        m_blood = m.m_blood;
        m_skill = m.m_skill;

        g_line++;
        cout << g_line << "行:Monster(const Monster &m)拷贝构造函数被调用" << endl;
    }

    void setBlood(const int blood)
    {
        m_blood = blood;
    }
    int getBlood()
    {
        return m_blood;
    }

    void setName(const int name)
    {
        m_name = name;
    }

    string getName()
    {
        return m_name;
    }

    //释放技能
    void spell(Monster &dest)
    {
        m_skill.spell(*this, dest);
    }

    ~Monster()
    {
        g_line++;
        cout << g_line << "行:~Monster()析构函数被调用" << endl;
    }

    void print_monster_info()
    {
        g_line++;
        cout << g_line << "行:怪物id = " << m_monsterId << ",名字 = " << m_name << ",血量 = " << m_blood <<  endl;
    }

    private:
    int m_monsterId; //怪物id
    string m_name; //怪物名字
    int m_blood; //血量
    Skill m_skill; //技能
};

//施法
void Skill::spell(Monster &src, Monster &dest)
{
    switch (m_skillType)
    {
        case SUB_DEST_BLOOD_ADD_SELF_BLOOD:
        {
            //dest
            int destBlood = dest.getBlood();
            destBlood -= m_val;
            if (destBlood < 0)
                destBlood = 0;
            dest.setBlood(destBlood);

            //src
            int srcBlood = src.getBlood();
            srcBlood += m_val;
            if (srcBlood < 0)
                srcBlood = 0;
            src.setBlood(srcBlood);

            g_line++;
            cout << g_line << "行:" << src.getName() << " 攻击了 " << dest.getName() << endl;
            g_line++;
            cout << g_line << "行:" << src.getName() << "的血量增加到:" << src.getBlood() << endl;
        g_line++;
        cout << g_line << "行:" << dest.getName() << "的血量减少到 " << dest.getBlood() << endl;
            break;
        }
        default:
        g_line++;
        cout << g_line << "行:技能类型未处理:" << m_skillType << endl;
    }
}

int main(int argc, char *argv[])
{
    Monster m1(10001, "雪女", 10000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 1000);
    Monster m2(10002, "紫衣仙子", 20000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 2000);
    m1.print_monster_info();
    m2.print_monster_info();

    m1.spell(m2);    
    return 0;
}

接下来我们再根据打印结果进行代码分析:

Monster m1(10001, "雪女", 10000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 1000);
另一个类的对象可以作为类的成员时,会先构造对象成员,再构造改该类,析构则刚好相反,先析构
该类,再析构对象成员。所以执行该语句,调用构造函数的顺序为:
(1)Skill类有参构造函数被调用
(2)Monster类有参构造函数被调用

Monster m2(10002, "紫衣仙子", 20000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 2000);
另一个类的对象可以作为类的成员时,会先构造对象成员,再构造改该类,析构则刚好相反,先析构
该类,再析构对象成员。所以执行该语句,调用构造函数的顺序为:
(1)Skill类有参构造函数被调用
(2)Monster类有参构造函数被调用

main函数执行结束时,会调用析构函数释放资源,调用析构函数的顺序为:
(1)m2被析构:Monster类析构函数被调用
(2)m2的m_skill对象成员被析构:Skill类析构函数被调用
(3)m1被析构:Monster类析构函数被调用
(4)m1的m_skill对象成员被析构:Skill类析构函数被调用
静态成员

静态成员包括:

  1. 静态成员变量:就是在成员变量前加上关键词static修饰的成员变量

  1. 所有对象共享一份数据

  1. 可以通过类名进行访问:Monster::ms_counter;

  1. 可以通过对象进行访问:Monster m; m.ms_counter;

  1. 在编译阶段分配内存

  1. 类内声明,类外初始化

  1. 有(public,protected,private)访问权限

  1. 静态成员函数:就是在成员函数前加上关键字static修饰的成员函数

  1. 所有对象共享同一个函数

  1. 可以通过类名进行访问:Monster::getMonsterCounter();

  1. 可以通过对象进行访问:Monster m; m.getMonsterCounter();

  1. 静态成员函数的函数体内只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数

  1. 有(public,protected,private)访问权限

example:测试静态成员变量,所有对象共享一份,类内声明,类外初始化,以及两种访问方式

#include <iostream>
using namespace std;

class Monster
{
    public:
    Monster():m_monsterId(0)
    {
        ms_counter++;
    }
    Monster(const int monsterId):m_monsterId(monsterId)
    {
        ms_counter++;
    }
    Monster(const Monster &m)
    {
        m_monsterId = m.m_monsterId;
        ms_counter++;
    }

    ~Monster()
    {
        ms_counter--;
    }

    static int ms_counter; //怪物个数

    private:
    int m_monsterId; //怪物id
};

int Monster::ms_counter = 0; //静态成员类外初始化

int main(int argc, char *argv[])
{
    //1.静态成员用类名进行访问
    cout << "ms_counter = " << Monster::ms_counter << endl;;

    //2.静态成员用对象进行访问
    Monster m1;
    cout << "ms_counter = " << m1.ms_counter << endl;
    Monster m2;
    cout << "ms_counter = " << m2.ms_counter << endl;
    return 0;
}

需要注意的是,静态成员变量也有(public,protected,private)访问权限的,如果我们将以上代码中的,静态成员变量声明为private权限,类外将不能对静态成员变量进行访问

example:测试静态成员函数所有对象共享一份,静态成员函数的函数体内只能访问静态成员变量或静态成员函数,不能访问非静态成员变量和非静态成员函数。以及两种访问方式

#include <iostream>
using namespace std;

class Monster
{
    public:
    Monster():m_monsterId(0)
    {
        ms_counter++;
    }
    Monster(const int monsterId):m_monsterId(monsterId)
    {
        ms_counter++;
    }
    Monster(const Monster &m)
    {
        m_monsterId = m.m_monsterId;
        ms_counter++;
    }

    ~Monster()
    {
        ms_counter--;
    }

    static int getMonsterCounter()
    {
        return ms_counter;
    }

    static void setMonsterCounter(const int counter)
    {
        ms_counter = counter;
        cout << "ms_counter = " << getMonsterCounter() << endl;
        //m_monsterId = 90001; //错误:静态成员函数只能访问静态成员变量或静态成员函数
    }

    private:
    static int ms_counter; //怪物个数

    int m_monsterId; //怪物id
};

int Monster::ms_counter = 0; //静态成员类外初始化

int main(int argc, char *argv[])
{
    //1.静态成员用类名进行访问
    cout << "ms_counter = " << Monster::getMonsterCounter() << endl;;

    //2.静态成员用对象进行访问
    Monster m1;
    cout << "ms_counter = " << m1.getMonsterCounter() << endl;
    Monster m2;
    cout << "ms_counter = " << m2.getMonsterCounter() << endl;
    return 0;
}

需要注意的是,静态成员函数也有(public,protected,private)访问权限的,如果我们将以上代码中的,静态成员函数声明为private权限,类外将不能对静态成员函数进行访问

好了,关于C++面向对象编程之三:初始化列表、类对象作为类成员、静态成员,先写到这。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值