命名控制

对于对象(或变量)使用static修饰,表明了两点信息:
一是该变量在静态存储存创建,main结束时它的生命才结束。
二是该变量最多只被初始化一次(可能一次也没有)。

{
 static const char * pStr;   // const意味pStr指向的内容不能改变。static意味着在静态数据区存放这个变量,而且在这个地方,编译器会加上把pStr初始化的语句即把pStr置为0,而且这个初始化动作只会在程序运行到这里时执行一次,以后即使再运行到这里也不再执行初始化的操作。
 ...
}

对于内置类型的static变量,如果没有初始化赋值(如static const char * pStr = 0;),则编译器会自动加上合适的0值。编译的时候只是在静态存储区分配内存,但并不初始化这个内存--初始化这个内存是在程序第一次运行到static变量定义的地方而进行的。
对于自定义类型的static对象,编译器要插入相应的构造函数来对这个static对象进行初始化,当然也是在程序第一次运行到定义处才进行。
class Y
{
 int  i;
public:
 Y( int n ) : i(n) {}
 ~Y( ) {}
};

void testStatic( )
{
 static  Y  y1(10); // 编译器在这里插入构造函数但只在第一次运行到这里时才执行
 //static  Y  y2;  //error,已经提供了构造函数则编译不再提供默认的构造函数,即没有无参的构造函数了
}

全局的对象或变量也在静态存储区创建,而且,它在进入main函数之前就创建了--如果它有构造函数则在进入main之前就执行了构造函数。
class  obj
{
 char c;
public:
 obj( char C ) : c(C) { cout << c << endl;}
 ~obj( ) { cout << "~" << c << endl; }
};

obj  A('a');  // 在进入main之前这个对象的构造函数就被调用了

void f( )
{
 static obj B('b');
 static obj C('c'); // 在出main函数时C先于B销毁,因为static的销毁顺序与创建相反
}

void g( )
{
 static obj D('d');
}


void main( )
{
 cout << "in main" << endl; 
 f( );
 //g( );  // D对象分配了内存,但没有初始化的机会,因为函数没有被调用
 cout << "leave main" << endl;
}
输出:
a
in main
b
c
leave main
~c
~b
~a


对于类里面声明的变量,或函数里面的局部变量,它们是没有连接的,所以如果给它们加static则表示它们要在静态存储区里面分配空间,而跟它们的可见性没有任何关系。对这些变量加extern是没有任何意义的。

对于文件范围内的变量(非类里面声明的,非函数里面定义的),它们本身就是在静态存储区分配的空间的,如果给它们加上static,则是为了改变它们的可见性,即加了static后它们就只在它们的编译单元(.cpp文件)里面可见,而对于别的编译文件不可见(即别的文件用这个名字不会出现冲突)。如果加上extern或不加,则表示这些变量是全局可见的(即所有的编译单元都可见)。

对于函数,加或不加extern表明这个函数是全局可见的;加static则表明这个函数只对它自己的编译单元可见。


名字空间的引入是为了避免名字冲突。
namespace thisNamespaceIsSoLong
{
  int  n = 10;
// ...
}
namespace TN = thisNamespaceIsSoLong; // 起个别名
cout << TN::n << endl;


类的静态数据成员在静态存储区里面分配内存,而且这个类的所有对象共享这一个内存(只有一份)。
这些静态的数据成员在类里面声明,然后必须在类的外面(如cpp文件里)进行定义(只定义一次):
class A {
  static int i;  // static数据成员声明
public:
  //...
};
在cpp文件里面:
int A::i = 10;  // 在这里定义,仅一次

///////// 静态数据成员的初始化表达式是在类的范围内
int  x = 100;

class  withStatic
{
 static int  x;
 static int  y;
public:
 void print( ) const
 {
  cout << "withStatic::x == " << x << endl;
  cout << "withStatic::y == " << y << endl;
 }
};

int withStatic::x = 1;
int withStatic::y = x + 1;  //静态数据成员的初始化表达式是在类的范围内,所以这里的x是指类里面的x。

void testStatic( )
{
 withStatic  ws;
 ws.print( ); // 输出1, 2
}

//////// 类静态数组的初如化:
class  Values
{
 static const int size;
 static const float talbe[4];
 static char  letter[3];
};

const int Values::size = 100;
const float Values::talbe[4] = {1.2f, 2.3f, 3.4f, 4.5f};
char Values::letter[3] = {'a', 'b', 'c'};

//////////////// 代替enum的做法
class  X {
static const int size;  // enum {size = 100};
int array[size];  // enum里面只能是整数
public:
  // ...
};

const int size = 100;


嵌套类里面可以使用static数据成员,但函数里面的局部类不能使用static数据成员。


static成员函数没有this指针,所以它不能访问非static的数据成员,也不调用非static的成员函数。
static成员函数服务于类而不是具体的对象,可以由对象或类名调用。
注意,非static的成员函数是可以访问static数据成员和调用static成员函数的。

///////// 一个只有一个对象的类:
class egg
{
 static egg E; // 类里面的static对象,这是这个类的唯一对象
 int  i;
 egg( int n = 0 ) : i(n) {}; // 构造函数是private的,所以不能再产生对象

public:
 static  egg* Instance( ) { return &E; } // static函数访问static数据
 int value( ) const { return i; }
};

egg  egg::E( 100 );  // 定义这个唯一的对象

// 测试代码:
void  testStatic2( )
{
 //egg  e;  // error,private的构造函数
 cout << egg::Instance()->value( ) << endl;;
}

 

extern "C" float f(char a, int b);

extern "C"
{
  float f(char a, int b);
  void g(double d );
}
表示"C"后面的函数是使用C连接的,所以C++编译器不会再做名字的转换--比如它可能转换出这样的名字:_f_char_int,现在加了extern "C"后,就保留原有的名字_f。在使用C库时,这种方法能够解决连接的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值