私有成员:静态const与仅const

时间:2009-12-21 00:01:58

标签: c++

我正在尝试确定当一个对象具有一些不会改变的特征时,最佳选择是什么,并且在整个函数中都需要它。

  1. 静态const成员
  2. Const成员
  3. 在我看来,静态成员的真正原因是拥有一个可以更改的变量,从而影响同一个类的所有其他对象。但是,我有人建议将类“不变量”作为静态const成员。我正在寻找有关建立类常量的推荐方法的一些见解,以及原因。

5 个答案:

答案 0 :(得分:16)

“不会改变”不够精确。这里的主要问题是类的不同对象是否需要具有这些const成员的不同值(即使它们在对象的生命周期内没有改变),或者所有对象都应该使用(共享)相同的值。

如果该类的所有对象的值相同,那么它当然应该是该类的static const成员。

如果不同的对象可能需要不同的值,那么它应该只是一个非静态const成员。

答案 1 :(得分:14)

当该成员未按实例更改时,应使用const成员。当该成员不按类别更改时,应使用static const成员。换句话说,无论您创建多少个实例,static const成员在所有实例之间保持固定,而const成员仅对特定实例保持不变。

我不确定这是不是你要找的东西,因为这只是对它们行为方式的解释,但我希望它有所帮助。

答案 2 :(得分:1)

一个原因是常规const成员将占用更多内存...即,对于您创建的类的每个对象,一个const成员对象将包含在该对象中并初始化。

另一方面,如果它是一个静态const成员,那么无论您创建的类的对象有多少,都只会创建和初始化一个对象,并且所有类对象将共享同一个对象。

为了演示,尝试两种方式编译,创建多个对象,并执行printf(“%p”,& theConstMemberObject)......当它是静态的时,你会看到它们都打印相同的指针值;当它不是静态时,它们每个都有自己的对象,因此它们每个都会打印不同的指针值。

答案 3 :(得分:0)

您可以将成员变量设为static const,因为在它不变的情况下,您可以重复使用它的所有实例共享的相同副本。而不是每个实例都有自己的(相同的)常量值副本。

你会期望编译器足够聪明,可以为你做这个优化,我怀疑它确实如此。这是一个很好的习惯。

答案 4 :(得分:0)

我的偏好是不使用static const成员,因为它似乎总是创建比const成员更多的耦合;有时混淆钻石继承层次结构,其中最终类继承自2个超类(1个类继承public;另一个继承virtual public)然后定义指向动态的static const成员通过newmalloccalloc等内存区域会导致double free错误。

e.g。这是一个简单的钻石继承情况的输出

ray:~ ray$ ./multiinheritance 
Base() called 
Derived1() called 
Base() called 
Derived2() called 
Final() called
~Final() called
~Derived2() called
~Base() called
freeing memory
~Derived1() called
~Base() called
freeing memory
multiinheritance(475) malloc: *** error for object 0x100150: double free
*** set a breakpoint in malloc_error_break to debug
ray:~ ray$ 

以下是代码:

#include <iostream>
#include <string>

class Base {
public:
    Base() {
        std::cout << "Base() called " << std::endl;
    }
    virtual ~Base() {
        std::cout << "~Base() called" << std::endl;
        std::cout << "freeing memory" << std::endl;
        delete i;
    }
    static const int* i;
};

const int* Base::i = new int[5];

class Derived1 : virtual public Base {
public:
    Derived1() {
        std::cout << "Derived1() called " << std::endl;
    }
    virtual ~Derived1() {
        std::cout << "~Derived1() called" << std::endl;
    }
};
class Derived2 : public Base {
public:
    Derived2() {
        std::cout << "Derived2() called " << std::endl;
    }
    virtual ~Derived2() {
        std::cout << "~Derived2() called" << std::endl;
    }
};

class Final: public Derived1, public Derived2 {
public:
    Final() {
        std::cout << "Final() called" << std::endl;
    }
    ~Final() {
        std::cout << "~Final() called" << std::endl;
    }
};

int main(int argc, char** argv) {
    Final f;
return 0;
}