C++不同的数据成员类型

C++不同的数据成员类型

C++为数据成员提供了多种选择,除了在类中简单地声明数据成员外,还可以创建static数据成员(类的所有对象共享)、const数据成员、引用数据成员、const引用数据成员和其他成员。本文将解释这些不同类型的数据成员。

静态数据成员

有时让类的所有对象都包含某个变量的副本是没有必要的,数据成员可能只对类有意义,而每个对象都拥有其副本是不合适的。C++用static数据成员解决了这个问题。static数据成员属于类但不是对象的数据成员,可将static数据成员当作类的全局变量。

class Spreadsheet
{
private:
    static size_t ms_counter; // 不能在此初始化值,也不能在构造函数内初始化,只能在类外初始化
};

不仅要在类定义中列出static类成员,还需要在源文件中为其分配内存,通常是定义类方法的那个源文件。还可以初始化static成员,但注意与普通的变量和数据成员不同,默认情况下它们会初始化为0。static指针会初始化为nullptr。示例:为ms_counter分配空间并初始化为0的代码

size_t Spreadsheet::ms_counter;

静态数据成员默认情况下初始化为0,但是如果有需要,可以将它们显示的初始化为0。

size_t Spreadsheet::ms_counter{0};

内联变量

从c++17开始,可以将静态数据成员声明为inline。这样做的好处就是不必在源文件中为它们分配空间。

class Spreadsheet
{
private:
    static inline size_t ms_counter{0}; // 之前类外初始化的代码可以删除了
};

在类方法内访问静态数据成员

在类方法内部,可以像使用普通数据成员一样使用静态数据成员。例如,为Spreadsheet类创建一个m_id成员,并在Spreadsheet构造函数中用ms_counter成员初始化它。

class Spreadsheet
{
public:
    Spreadsheet() : m_id{ms_counter++} {};

private:
    size_t m_id{0};
    static size_t inline ms_counter{0};
};

本例中,假使一旦给某个对象指定id,就不应该改变。所以在拷贝赋值运算符中不应该复制id,因此可以把m_id设置为const数据成员。

class Spreadsheet
{
private:
    const size_t m_id{0};
};

由于const数据成员一经创建就无法更改,例如,无法在构造函数体内初始化它们。此类数据成员必须直接在类定义内部或构造函数初始化器中初始化,这也意味着不能在赋值运算符中为此类数据成员赋值。

在方法外访问静态数据成员

访问控制限定符适用于static数据成员,ms_counter是private的,因此不能在类方法外访问。如果ms_counter是public的,就可以在类方法外访问,具体方法是用 :: 作用域解析运算符指出这个变量是Spreadsheet类的一部分。

int c { Spreadsheet::ms_counter };

然而,不建议使用public数据成员。应该提供public的get/set方法来授权访问权限。如果要访问static数据成员,可以实现static的get/set方法。

const static数据成员

类中的数据成员可声明为const,意味着在创建并初始化后,值不能再改变。如果某个常量只适用于类,应该使用static const(或者const static)数据成员,也称为类常量,而不是全局常量。可以在类定义中和初始化整型和枚举类型的static const数据成员,而不需要将其指定为内联变量。

例如,创建类指定了电子表格的最大高度和宽度,如果用户想要创建的电子表格的高度或者宽度大于最大值,那么就改用指定的最大值。可将最大高度和宽度设置为Spreadsheet类的static const成员。

class Spreadsheet
{
public:
    static const size_t MaxHeight{100};
    static const size_t MaxWidth{100};
    Spreadsheet(size_t width, size_t height)
        : m_id{ms_counter++},
          m_width{min(width, MaxWidth)},
          m_height{min(height, MaxHeight)} {}

private:
    size_t m_width;
    size_t m_height;
    const size_t m_id{0};
    static size_t inline ms_counter{0};
};

这些常量也可以作为构造函数的参数的默认值。需要注意的是,只能为一组连续的参数(从右向左)指定默认值。示例:

Spreadsheet(size_t width = MaxWidth, size_t height = MaxHeight);

引用数据成员

假设Spreadsheet类需要用到一个控制电子表格的类SpreadsheetApplication,示例:

class SpreadsheetApplication {};
class Spreadsheet
{
public:
    static const size_t MaxHeight{100};
    static const size_t MaxWidth{100};
    Spreadsheet(size_t width, size_t height, SpreadsheetApplication &app)
        : m_id{ms_counter++},
          m_width{min(width, MaxWidth)},
          m_height{min(height, MaxHeight)},
          m_app{app} {}

private:
    size_t m_width;
    size_t m_height;
    const size_t m_id{0};
    static size_t inline ms_counter{0};
    SpreadsheetApplication &m_app;
};

将一个SpreadsheetApplication引用作为数据成员添加进来,在此情况下建议使用引用而不是指针,因为Spreadsheet总会指向一个SpreadsheetApplication,而指针则无法保证这一点。

注意:在构造函数中,每个Spreadsheet都得到了一个应用程序引用。如果不指向某些事物,引用将无法存在,因此在构造函数初始化器中必须给m_app指定一个值!

在拷贝构造函数中也必须初始化这个引用成员。再次提醒,在初始化一个引用之后,不能改变它指向的对象。因此无法在赋值运算符中对引用赋值。这就意味着根据使用的情形,可能无法为具有引用数据成员的类提供赋值运算符。这种情况下,通常将赋值运算符标记为删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值