文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>c++ 中 const ,static , static const, const static 辨析...

c++ 中 const ,static , static const, const static 辨析...

时间:2010-08-08  来源:msjianghu

在类的外部(比如一个头文件里),情况较为容易分析:   1. const variable 在定义时必须初始化,是文件内部可见。这是因为c++中,const变量默认是内连接的(internal linkage)。(原因见后)      也就是说它只能在定义它的文件内部使用,连接时其它编译单元看不见它。      例如:            const int i = 0 ;    // 而且编译器一般不为const variable分配内存,而是将它放入                                         //符号表(symbol table),以便编译时实现常量折叠(constant folding)。            但是,若是进行如下定义:             extern const int i;      则将强制编译器为变量分配内存空间。因为,extern 意味着使用外部链接(external linkage)。      当你对一个const variable 去地址时,也会进行内存分配。例如:             const int i = 9;             long address =  (long ) &i;           由上面我们可以看出,编译器并不总是能够成功的避免为常量分配内存,上述两种情况就必须分配内存。所以const variable      如果默认是外连接,就有可能导致同一个常量在不同的cpp文件中都分配了内存(比如多个文件中都要求取得一个常量的地址)。      这就会让编译器认为同一常量出现重复定义而报错。      而如果常量默认为内连接,这就意味着该常量只在当前定义它的文件内部有效,而连接器不会试图去连接其他编译单元里的常量。      这样,即使多个cpp文件中有相同名字的一个常量也不会发生冲突。如此,编译器就可有效的实现常量折叠(constant folding)      另外,有上面我们知道,在C++中,        const int i = 0;      i的值是在符号表里,这就意味着i的值是编译期间可见的。所以,如下代码是可行的:        const  int i = 0;        const  int j = i + 1;  // ok! 因为i的值在编译时知道,j也是const          这里和C中的const有所不同,C中的const默认为外连接,所以总是会为其分配内存空间。这就意味着,在C中        const  int bufsize = 100;       在编译期间,编译器并不知道 bufsize的值。所以,下面的代码有误:        const  int bufsize  = 100;        char buf[bufsize]; // error       还有一点不同的是:        const int bufsize;       这句代码在C中是可以的,编译器认为这是一个声明,某处有为这个常量分配内存,但是在C++中,这句代码是不可以的。       可以有两种方式修改:         (1) const int bufsize = 100;  //定义时初始化         (2) extern const int;  // 当然,这句在C中也是可以的 类外部的情况较为简单,下面我们看看在类的内部。 *** const variable 和 static variable的不同:        1.const定义的常量在函数执行之后其空间会被释放,而static定义的静态常量在函数执行后不会被释放其空间。        2.static 表示的是静态的。类的静态成员函数,成员变量是和类相关的,不是和类的具体对象相关,即使没有具体的对象,也能           调用类的静态成员函数,成员变量。一般的静态函数几乎就是一个全局函数,只不过它的作用域限于包含它的文件中。
     3.在c++中,static静态成员变量不能在类内部初始化。
         在c++中,const常量成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数。
***
const variable:        1.const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象      其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道      const 数据成   员的值是什么。        2.const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中          的枚举常量来实现,或者static const。        3.C++中的const与C中的const不再一样。它会在每一个对象中占有一定的内存空间,代表一个值,这个值         一旦被初始化就不能在改变。意味着:This is a constant for the lifetime of the object. 但是,每一个          该类型的不同的对象可以有不同的该值。   如:  

class Test
{
public:
  Test(): a(0){}
  enum {size1=100, size2 = 200 };
private:
  const int a;        // 只能在构造函数初始化列表中初始化
  static int b;
  const static int c; // 与static const int c;相同,可以在这里定义
}
int Test::b = 0; //不能以成员列表初始化,不能在定义初始化,不属于某个对象

const int Test::c = 0;

****

const 成员函数,主要的目的是防止修改对象的内容。即:int Fun() const; 不可以修改对象的数据,可以访问对象的数据,访问成员函数时,只能是const的,不能是non_const的成员函数。

static成员函数,主要的目的是作为类作用域的全局函数。不能访问类的非静态数据成员。类的静态成员函数的没有this指针,这导致:

1.不能直接存取类的非静态成员变量

2.调用非静态成员函数不能被声明为virtual
 

class foo
{
private:
  const int i = 100; // error !!!
public:
  foo(){}
  ......
};

这样的初始化方式是不能通过编译的,因为在类对象里进行了存储空间分配,编译器不能知道const的内容是什么,所以不能把它用作编译期间的常量。这意味着对于类里的常数表达式来说,const就像它在C中一样没有作用。因此这个初始化工作必须发生在构造函数里,并且,要在构造函数的某个特别的地方。因为const必须在建立它的地方被初始化,所以在构造函数的主体里,const必须已初始化了,否则,就只有等待,直到在构造函数主体以后的某个地方给它初始化,这意味着过一会儿才给const初始化。当然,无法防止在在构造函数主体的不同地方改变const的值。

构造函数初始化表达式:

class foo
{
private:
  const int i;
public:
  foo():i(0){}
  ......
};

如果构造函数是在类外定义,则可以这样写:

class foo
{
private:
  const int i;
public:
  foo():i(0){}
  ......
};


foo:foo():i(0)

{

  ...



***

类里的static成员初始化:

类中的static变量是属于类的,不属于某个对象,它在整个程序的运行过程中只有一个副本,因此不能在定义对象时对变量初始化,就是不能用构造函数来初始化。其正确的初始化方式是:

<数据类型><类名> ::<静态数据成员名> = <值> ,例如:

class foo
{
private:
  static int i;
public:
  foo();
  ......
};
int foo::i = 100;


这表明:

(1)初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。

(2)初始化时不加该成员的访问权限控制符private,public等。

(3)初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。

(4)设定static成员变量初值时,不受任何存取权限的影响。

(5)请注意,static成员变量的类型也出现在初值设定语句中。

3.类里的static const 和const static成员初始化:

const成员要在构造函数初始化,而static成员在需要在在类体外初始化,那么static const 和 const static 的成员应该在哪里进行初始化呢?这两个写法又会有什么不一样吗?其实他俩都一样。在Thinking in c++ 英文版Chapter 8 中有如下例子:

class StringStack{
  static const int size = 100 // 可以在此初始化 represents the size of a stack

  const static  int m_size; // 也可先不初始化,size 也是

  const string* stack[size];

  int index;

public:

  StringStack();

  void push(const string* s);

  const string* pop();
};
const int StringStack::m_size = 100; // 也可以在这里初始化

 


它们没有区别,虽然 一个是静态常量, 一个是常量静态。 静态都将存储在全局变量区域,其实最后结果都是一样的。 可能在不同编译器内,不同处理,但是最后结果是一样的。

下面是一个完整的例子:

#ifndef A_H_
#define A_H_
#include<iostream>
using namespace std;

class A{
private:
  static int aa; //静态数据成员声明  不能在此初始化
  static const int count; //静态常量数据成员声明(可以在此初始化)
  const int bb; //常量数据成员   在构造函数的初始化列表进行初始化
public:
  A(int a);
  static void print(); //静态成员函数
};

A::A(int a):bb(a)

{ //常量成员的初始化
  aa += 1;
}

void A::print()

{
  cout << "connt=" << count<< endl;
  cout << "aa=" << aa << endl;
};

int A::aa = 0; //静态成员定义
const int A::count = 25; //静态常量成员初始化


#endif

int main()

{
  A a(10);
  A::print(); //通过类访问静态成员函数
  a.print();  //通过对象访问静态成员
}

总结一下:

 const成员要在构造函数的初始化列表初始化

 static成员在需要在在类体外初始化

 static const 和 const static 的成员即可在定义初始化也可在类体外初始化

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载