C++ 如何初始化静态类成员(静态成员必须在.cpp文件中初始化) |
您所在的位置:网站首页 › 纹身抽烟头像男霸气图片大全高清 › C++ 如何初始化静态类成员(静态成员必须在.cpp文件中初始化) |
一般来说,关于C++类静态成员的初始化,并不会让人感到难以理解,但是提到C++ 静态成员的"类内初始化"那就容易迷糊了。 我们来看如下代码: 我们需要判断上面的静态数据成员的声明和定义有没有错误,并解释原因。 首先,要谨记:通常情况下,不应该在类内部初始化成员,无论是否为静态成员。 其次,若一定要在类内初始化静态成员,那么就必须满足如下条件才行: 1) 静态成员必须为字面值常量类型的constexpr。 所谓的字面值类型就是通常遇到的:算术类型,引用,指针等。字面值常量类型就是const型的算术类型,引用,指针等。 所谓的constexpr,就是常量表达式,指值不会改变且在编译过程中就能得到计算结果的表达式。比如字面值,或者用常量表达式初始化的const对象也是常量表达式。为了帮助用户检查自己声明/定义的变量的值是否为一个常量表达式,C++11新规定,允许将变量声明为constexpr类型,以便由编译器来进行验证变量是否为常量表达式。 2)给静态成员提供的初始值,必须为常量表达式 注意:在C++ primer 第五版中说:只能给静态成员提供const 整数类型的类内初始值,且该const整数类型的初始值必须是常量表达式。我觉得是有误的!详情见后面分析。 有了这两条原则,我们就可以对上面的代码进行验证了。 1)static double rate = 6.5; 显然不满足第一条:因为rate不是常量类型。改成constexprt static const double rate = 6.5即可 从这里也可以看出初始值不一定必须为const 整数类型。 ps: 如果我们不再这里加入constexprt修饰符的话,编译器会提示错误:error: ‘constexpr’ needed for in-class initialization of static data member ‘const double Example::rate’ of non-integral type [-fpermissive] 大体意思就是,对于非const整数类型的初始值,如果它是常量表达式的话,我们需要手工在前面添加修饰符constexprt。 至于Example.cpp文件中的定义部分,由于我们已经在类内部进行了初始化,就不需要再在类外部进行定义了。如果非要定义的话,必须采用如下格式: //example.cppconstexpr const double Example::rate; //其中的const是可以删除的,因为constexprt本身就包含了const 2)static const int vecSize = 20; vecSize是const int类型的,且为常量表达式——满足第一条;提供的初始值为20,是一个常量表达式——满足第二条!且由于是const int型的,前面可以不用修饰符constexpr。 3)static vector vec(vecSize); 错误!vector是模板不是字面值常量类型,所以不满足第一条。应该改为 static vector vec; //仅仅且只能进行声明,不能定义 然后在Example.cpp中进行定义: static vector vec(Example::vecSize); 现在我们可以在Example.cpp中添加测试代码进行测试了: 按照前面的介绍,我们或许应该以下面这种方式初始化s: //B.cpp #include S B::s; //编译器会报错,因为S没有可以调用的构造函数 解决方法是定义一个静态方法,负责初始化静态成员s: //B.h class B { public: static S Init(); private: static S s; }; //B.cpp #include S B::Init() { .... return S::Instance(); } S B::s = B::Init(); //调用静态函数初始化静态成员 上例中,为了初始化类B的静态 成员s,我们定义了一个公有的静态方法Init(),它可以很好的工作。但是,在现实的工程中,我们很可能碰到更进一步的要求,就是希望Init()仅仅作为静态变量s的初始化器使用,而不能使用在程序中别的地方,但是我们又不能把Init()声明为private,这样Init()就不能被调用来初始化s了。解决的方法是使用内部类: //B.h class B { private: class C { public: static S InitB(); }; static S s; }; //B.cpp S B::C::InitB() { .... return S::Instance(); } S B::s = B::C::InitB(); //调用内部类的静态成员函数来初始化静态数据成员 因为C是B的内部类,C仅在B的作用域范围内可见,如果程序的其他地方调用了B::C::InitB(),编译器将报错,因为C不可访问。 最后说一下,从初始化的方式可以看出来,类的静态数据成员其实就是“带类名”的全局变量。 静态数据成员必须显式初始化,否则在类方法中操作该成员时,将报链接错误 undefined reference to `A::buf' (gcc中) |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |