• C++类作用域


    11.6 类作用域

    在类中定义的名称(如类数据成员和类成员函数名)的作用域都为整个类,作用域为整个类的名称只有在该类中是已知的,在类外是不可知的。因此,可以在不同类中使用相同的类成员名而不会引起冲突。

    Stock sleeper("Exclusive Ore", 100, 0.25); // create object
    sleeper.show(); // use object to invoke a member function
    show(); // invalid -- can’t call method directly
    
    • 1
    • 2
    • 3

    总之,在类声明或成员函数定义中,可以使用未修饰的成员名称(未限定的名称),就像ViewIk()调用disp()成员函数时那样。

    class Ik
    {
    private:
    	int fuss; // fuss has class scope
    public:
    	Ik(int f = 9) { fuss = f; } // fuss is in scope
    	void ViewIk() const; // ViewIk has class scope
        void disp() const;
    };
    void Ik::ViewIk() const //Ik:: places ViewIk into Ik scope
    {
    	cout << fuss << endl; // fuss in scope within class methods
        disp();//不需要限定修饰符
    }
    ...
    int main()
    {
    	Ik* pik = new Ik;
    	Ik ee = Ik(8); // constructor in scope because has class name
    	ee.ViewIk(); // class object brings ViewIk into scope
    	pik->ViewIk(); // pointer-to-Ik brings ViewIk into scope
    	...
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    11.6.1 类作用域常量

    有时候,类作用域常量很有用。例如,类声明可能使用字面值30来指定数组的长度,由于该常量对于所有对象来说是相同的,因此创建一个由所有对象共享的常量是个不错的主意。

    第一种方法实现类作用域常量:

    声明一个枚举。在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。

    class Bakery
    {
        private:
            enum {Months = 12};
            double costs[Months];
            ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意,用这种方式声明枚举并不会创建类数据成员。也就是说,所有对象中都不包含枚举。另外,Months只是一个符号名称,在作用域为整个类的代码中遇到它时,编译器将用12替换它。

    这里使用枚举只是为了创建符号常量,并不打算创建枚举类型的变量,因此不需要提供枚举名。在很多实现中,ios_base在其共有部分完成了类似的工作,诸如ios_base::fixed等标识符就来自这里。其中fixed是ios_base类中定义的典型的枚举量。

    第二种方法实现类作用域常量:使用static关键字

    如下所示,创建了一个名为Months的常量,该常量将与其他静态变量存储在一起,而不是存储在对象中。因此,只有一个Months常量,被所有Bakery对象共享。

    class Bakery
    {
        private:
            static const int Months = 12;
            double costs[Months];
            ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    11.6.2 作用域内枚举(C++11)

    11.6.2.1 传统枚举的弊端

    传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突。

    enum egg {Small, Medium, Large, Jumbo};
    enum t_shirt {Small, Medium, Large, Xlarge};
    
    • 1
    • 2

    这将无法通过编译,因为egg的Small和t_shirt的Small位于同一个作用域内,他们将发生冲突。

    11.6.2.2 C++11针对该弊端给出的解决方案
    11.6.2.2.1 作用域枚举定义

    C++提供了一种新枚举,其枚举量的作用域为类。

    enum class egg {Small, Medium, Large, Jumbo};
    enum class t_shirt {Small, Medium, Large, Xlarge};
    
    • 1
    • 2

    也可以使用struct代替class,无论使用哪种方式,都需要使用枚举名来限定枚举量:

    egg choice = egg::Large; // the Large enumerator of the egg enum
    t_shirt Floyd = t_shirt::Large; // the Large enumerator of the t_shirt enum
    
    • 1
    • 2

    枚举量的作用域为类,不同枚举定义中的枚举量就不会发生名称冲突了。

    11.6.2.2.2 作用域枚举安全机制

    C++11还提高了作用域内枚举的类型安全。在有些情况下,常规枚举将自动转换为整型,如将其赋值给int变量或用于比较表达式时,其作用域内枚举不能隐式的转换为整型。

    enum egg_old {Small, Medium, Large, Jumbo}; // unscoped
    enum class t_shirt {Small, Medium, Large, Xlarge}; // scoped
    egg_old one = Medium; // unscoped
    t_shirt rolf = t_shirt::Large; // scoped
    int king = one; // implicit type conversion for unscoped
    int ring = rolf; // not allowed, no implicit type conversion
    if (king < Jumbo) // allowed
    std::cout << "Jumbo converted to int before comparison.\n";
    if (king < t_shirt::Medium) // not allowed
    std::cout << "Not allowed: < not defined for scoped enum.\n";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    但是可以使用强制类型转换:

    int Frodo = int(t_shirt::Small); // Frodo set to 0
    
    • 1
    11.6.2.2.3 作用域枚举内存分配

    枚举用某种底层整型类型表示,在C++98中,如何选择取决于实现,因此包含枚举的结构的长度随系统而异。对于作用域内枚举,C++11消除了这种依赖性。默认情况下,C++11作用域内枚举的底层类型为int。另外,还提供了一种语法,可用于做出不同的选择:

    // underlying type for pizza is short
    enum class : short pizza {Small, Medium, Large, XLarge};
    
    • 1
    • 2

    short将底层类型指定为short。

  • 相关阅读:
    前后端连接-界面跳转,异步
    数分面试题2-牛客
    刷题——Python篇(2)类型转换
    CEX的梅克尔树储备证明是什么?
    墨刀基础篇(一) :2.常用组件(基础:其它)
    C# Socket通信从入门到精通(10)——如何检测两台电脑之间的网络是否通畅
    开放实验室管理系统 毕业设计 JAVA+Vue+SpringBoot+MySQL
    Ubuntu TDengine集群搭建
    leetcode-268.丢失的数字
    android 通过adb shell 命令获取最大打开文件数和当前打开文件数及串口使用率
  • 原文地址:https://blog.csdn.net/weixin_44410704/article/details/127923745