Empty Class(空类)的作用

假如有一个这样的类,没有数据成员和操作(除了本身默认存在的构造函数、复制构造函数、析构函数、copy assignment函数),那么,它能做什么?

class Empty
{
};

一开始我也是以为这样的空类能够有什么作用呢,直到我看了[1],才感叹自己如此肤浅(所以也建议你去看:)

先假设我们有个很傲娇的类,它不希望通过构造函数生成,也不希望别的对象对它赋值。很不巧,如果我们没有在类中声明复制构造函数或者赋值操作符,那么编译器会为我们默认生成。

那么如何防止这样的事情发生呢?
将复制构造函数和赋值操作符声明为私有

像这样:

class SomeClass
{
    private:
    SomeClass(const SomeClass&);
    SomeClass& operator=(const SomeClass&);
    ...
};

那么当有以下操作都是非法的:

//假如有SomeClass s;
SomeClass scopy(s);//error
s = scopy;//error

然而更加高级的做法是定义一个空类,将空类的复制构造函数和赋值操作符声明为私有,然后让SomeClass继承它。像这样:

class Empty
{
protected:
    Empty(){}                    //允许derived class调用
    ~Empty(){}
private:
    Empty(const Empty&);            //阻止了copying
    Empty& operator = (const Empty&);
};

class SomeClass: private Empty
{
    ...
};

当有人尝试拷贝SomeClass 对象时,编译器会试着去调用base class,也就是Empty 的 copy 构造函数,然后因为private 而告终。

另一个方面,一个空类没有数据成员,理应是不占内存的。
但是sizeof运用于空类的话,会发现空类大小为1。
引用[1]中的原话:

然而,由于技术上的理由,C++裁定凡是独立(非附属)对象都必须有非零大小
通常C++ 官方勒令默默安插一个char 到空对象内。

但,这个约束并不适用于derived class对象内的base class成分,因为它们并非独立。

也就是说,如下:

class SomeClass1
{
private:
    int x;
    Empty e;
};

class SomeClass2: public Empty
{
private:
    int x;
}:

sizeof(SomeClass1) == 8;
sizeof(SomeClass2) == 4;

Someclass1 占用内存肯定不等于一个int,而且因为内存对齐的原因,结果占用内存达到了8;

这是所谓的EBO(empty base optimization:空白基类最优化)

[参考资料]
[1] [1] Scott Meyers 著, 侯捷译. Effective C++ 中文版: 改善程序技术与设计思维的 55 个有效做法[M]. 电子工业出版社, 2011.(条款06:若不想使用编译器自动生成的函数,就该明确拒绝、条款39:明确而审慎地使用private 继承)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是编译器给出的警告信息,意思是在声明中使用了无用的存储类别说明符。这通常是因为在声明中使用了关键字,但没有给出具体的类型或变量名,导致编译器无法识别其作用。建议检查代码中的声明语句,确保每个声明都有明确的类型或变量名。 ### 回答2: 在C++中,存储类指定符用于指定变量或函数的存储方式,包括auto、register、static和extern等。如果在一个声明中使用了无用的存储类指定符,编译器会报出“useless storage class specifier in empty declaration”的错误。 声明是指没有提供任何变量名或函数体的声明。在C++中,声明通常用于在头文件中声明一些函数原型。例如: ```cpp void func1(); int func2(); ``` 这些声明中不包含任何实现细节,只是告诉编译器某些函数的存在,以便程序中的其他部分可以调用它们。 但如果在这些声明中使用存储类指定符,则会导致编译错误。例如: ```cpp auto void func1(); // 错误:无用的auto存储类指定符 static int func2(); // 错误:无用的static存储类指定符 ``` 这些错误告诉我们,在声明中使用存储类指定符是没有任何意义的。因为声明没有变量名或函数体,所以存储类指定符也不会有任何作用。 那么,如何避免这种错误呢?在声明中,只需省略存储类指定符即可。例如: ```cpp void func1(); int func2(); ``` 这样就能正确声明函数原型,而不会导致编译错误。 ### 回答3: “Useless storage class specifier in empty declaration”是指在C++程序中的声明中存在无用的存储类别说明符。一个声明是指只含有分号符号的语句,通常用于定义空类结构体。 在C++中,存储类别说明符主要包括auto、register、static和extern。它们用来定义变量的作用域和生存周期。但在声明中,这些说明符是无意义的,因为它们只应用于变量声明语句,而声明并不包含任何变量。 例如,以下代码展示了一个的结构体,其中包含无用的static存储类别说明符。 ``` struct EmptyStruct { static; }; ``` 编译器会在编译时报告警告或错误。因为static说明符对于的结构体是无效的,它不起任何作用。同样的,对于包含成员列表的空类,auto、register和extern等说明符也是无用的。 修正这个问题很简单,只需要从声明中去掉无用的存储类别说明符即可。 总之,在C++中使用无用的存储类别说明符将导致程序无法通过编译,这不仅浪费时间,还会影响代码的可读性和可维护性。因此,在编写代码时,我们应该避免使用无用的存储类别说明符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值