Benjamin

静以修身,俭以养德,非澹薄无以明志,非宁静无以致远。
随笔 - 397, 文章 - 0, 评论 - 196, 引用 - 0
数据加载中……

C++之构造函数(Constructors)和static

构造函数和静态成员:必须显式定义静态成员变量,不能出现在构造的初始化列表中
1  class Fred {
2  public:
3    Fred();
4    
5  private:
6    int i_;
7    static int j_;
8  }; 
Fred::Fred()
   : i_(
10)  // OK: you can (and should) initialize member data this way
   , j_(42)  // Error: you cannot initialize static member data like this
 {
   
 }
 
 
// You must define static data members this way:
 int Fred::j_ = 42
通常把静态成员的声明放到.H文件,定义放到.cpp中。如果没有定义,会出现 "undefined external" 的链接错误。
静态变量初始化顺序产生的错误是难以觉察,因为它发生在mian之前,如果你有两个静态成员x,y,分别位于两个文件x.cpp、y.cpp中,而y在初始化要调用x,这样的场景很常见,出错的几率有百分之五十。如果先初始化x,一切OK,如果先初始化y,那就惨了。例如:
1  // File x.cpp
2  #include "Fred.h"
3  Fred x; 
4 
1 // File y.cpp
2  #include "Barney.h"
3  Barney y; 
1  // File Barney.cpp
2  #include "Barney.h"
3  
4  Barney::Barney()
5  {
6    
7    x.goBowling();
8    
9  } 
解决这种静态成员初始化的方法很多,一个简单的方法就是用静态方法x()替代Fred x,然后返回这个Fred的引用,如下所示:
1  // File x.cpp
2  
3  #include "Fred.h"
4  
5  Fred& x()
6  {
7    static Fred* ans = new Fred();
8    return *ans;
9  } 
这个静态变量这初始化一次,以后将一直返回同样的Fred对象。这是修改后的代码
1  // File Barney.cpp
2  #include "Barney.h"
3  
4  Barney::Barney()
5  {
6    
7    x().goBowling();
8    
9  } 
第一次使用,Fred对象先被构造。但是这个解决方法使用时要慎重,在这里第一选择是使用静态成员,使用静态指针会有一些副作用,倒不是担心内存泄露,在程序退出时系统会自己释放这些堆空间。在使用静态变量时要保证第一次使用前被初始化,最后一次使用后被析构,在这里我们要注意的是析构函数的代码。如果静态变量a、b、c在构造时调用ans没问题,但是在析构时如果还调用ans,程序极有可能崩溃。这种应用在实际中并不多见,解决的方法有三种,待以后的主题中在讲。
在这里有个static initialization和static deinitialization,前者意义大家都知道,后者则是去初始化指的是在应用之前被别的代码给析构了,导致我们用的这个静态量没有初始化,这个是很致命的,尤其在静态指针中,表现的更为明显。
当然static这个关键字也并非一无是处,下面的代码中的错误就可以用staic来解决:
 1 #include <iostream>
 2  
 3  int f();  // forward declaration
 4  int g();  // forward declaration
 5  
 6  int x = f();
 7  int y = g();
 8  
 9  int f()
10  {
11    std::cout << "using 'y' (which is " << y << ")\n";
12    return 3*+ 7;
13  }
14  
15  int g()
16  {
17    std::cout << "initializing 'y'\n";
18    return 5;
19  } 
这段代码显然不能通过编译,下面通过static改变了初始化的顺序
 1 #include <iostream>
 2  
 3  int f();  // forward declaration
 4  int g();  // forward declaration
 5  
 6  int x = f();
 7  int y = g();
 8  
 9  int f()
10  {
11    std::cout << "using 'y' (which is " << y << ")\n";
12    return 3*+ 7;
13  }
14  
15  int g()
16  {
17    std::cout << "initializing 'y'\n";
18    return 5;
19  }
 1 #include <iostream>
 2  
 3  int f();  // forward declaration
 4  int g();  // forward declaration
 5  
 6  int x = f();
 7  int y = g();
 8  
 9  int f()
10  {
11    std::cout << "using 'y' (which is " << y << ")\n";
12    return 3*+ 7;
13  }
14  
15  int g()
16  {
17    std::cout << "initializing 'y'\n";
18    return 5;
19  } 

但是上面的更改只限于编译器的内置数据类型,而不是用户自定义的数据类型。

posted on 2010-05-08 22:27 Benjamin 阅读(1440) 评论(0)  编辑 收藏 引用 所属分类: C/C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理