您的位置:首页 > 编程语言 > C语言/C++

C++中const与static使用的几个要点

2016-12-28 23:17 387 查看

(1) const使用要点

为什么要使用const?

const是定义常量的,而且const定义的常量是有数据类型的,而宏常量是没有数据类型的,所以编译器可以对const常量进行类型安全检查,而对宏常量只是简单的替换,没有类型安全检查,容易出错。

const起到保护的作用,防止修改。

const还有一个关键作用是做函数重载。

节省空间:const定义的常量只是给出了对应的内存地址,而#define定义的常量在内存中有若干拷贝。

提高效率:编译器通常不会为普通的const常量分配存储空间,只是将他们保存在符号表中,即它是一个编译期间的常量,没有存储与读取的操作,效率很高。

指针与const

  指针与const搭配的两种形式:

  const int* p;   表示指向的内容是常量,不可变。

  int* const p;  表示这个指针本身是常量,不可变。

  const int* const p;  都不可变

 

const与参数传递

const修饰参数的主要意义是参数在函数内不可以改变,所以对一般类型的形参修饰没有意义。

如果形参是指针,const int* p这种修饰是有意义的,表明指针指向的内容是不能修改的,但int* const p是没有意义的。

const经常和引用一起用,表明引用的参数在函数内是不可以改变的,这和普通函数按值传递的效果相同,不同之处在于:按值传递是建立对象的副本,然后传递的,而常引用是直接传递地址,所以效率更高。

const修饰函数返回值,是说函数的返回值是常量,不能修改。

对返回值是指针时,则指向的内容不能被修改,且只能赋给const型指针

如果返回值为某个对象为const或某个对象的引用为const ,则返回值具有const属性,则返回实例只能访问类a中的公有数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。

注意一点,以下情况在c++中会被报错为重复定义,而不是重载。

int fun1(int a,int b);
const int fun1(int a,int b);


const与类

const修饰成员变量 只能在初始化列表中赋值,只有这一种赋值方法。

const修饰成员函数,则该函数是不允许修改类的数据成员的。(注意:准确的来说是不允许改变非静态数据成员,可改变静态数据成员)

常对象只能调用被声明为const的成员函数(构造与析构除外)。

class Screen{
public:
char get(int x,int y);
char get(int x,int y)const;
};

const Screen a;
Screen b;
a.get(0,0);   //调用const成员函数
b.get(0,0);   //调用非const成员函数


  其实这个就是之前提到的基于const的函数重载。

(2)static使用要点

为什么要用static

隐藏:当同时编译多个文件时,所有未加stati
4000
c前缀的全局变量和函数都具有全局可见性。如果加了static,就会对其它源文件隐藏。

静态全局变量不能被其它文件所用(全局变量可以);其它文件中可以定义相同名字的变量,不会发生冲突(自然了,因为static隔离了文件,其它文件使用相同的名字的变量,也跟它没关系了);

静态函数跟静态全局变量的作用类似(静态函数不能被其它文件所用; 其它文件中可以定义相同名字的函数,不会发生冲突;)

静态局部变量:延长变量的生存期。

用于函数体内部修饰变量,这种变量的生存期长于该函数

先说明下内存分布的情况:对于一个完整的程序,在内存中的分布情况如下: 

栈区: 由编译器自动分配释放,像局部变量,函数参数,都是在栈区。会随着作用于退出而释放空间。

堆区:程序员分配并释放的区域,new

全局数据区(静态区):全局变量和静态便令的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束释放。

代码区

而静态变量就是存储在静态区的,它随着第一次函数的调用初始化,仅初始化这一次,第二次调用这个函数时不会再初始化,而是直接跳过,然后该变量不会随着函数调用结束而销毁。

静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0

它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,也就是不能在函数体外面使用它(局部变量在栈区,在函数结束后立即释放内存)

用于类:下面讲

static与类

静态数据成员:

对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。

静态数据成员存储在全局数据区

因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它

类的静态数据成员有两种访问形式:

<类对象名>.<静态数据成员名> 或

<类类型名>::<静态数据成员名>

静态数据成员是静态存储的,所以必须对它进行初始化。(程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)

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

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

初始化时使用作用域运算符来标明它所属类;

所以我们得出静态数据成员初始化的格式:

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

class A{

public:

static int a;

};

int A::a = 3; //初始化

静态成员函数

与静态数据成员一样,静态成员函数为类的全部服务而不是为某一个类的具体对象服务。

普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。但是与普通函数相比,静态成员函数不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数

调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:

<类名>::<静态成员函数名>(<参数表>)

调用类的静态成员函数。

const static int/static const int

对于static const成员和const static成员而言,只有int类型可以在内部初始化,任何类型都可以在类外初始化,但是不可以在构造函数列表初始化。(static const int a=1;并不分配内存,编译时直接将a换成1,放到常量表中)

总结c++类中特殊成员变量的初始化

#include <iostream>
using namespace std;

class BClass
{
public:
BClass() : i(1), ci(2), ri(i){} // 对于常量型成员变量和引用型成员变量,必须通过参数化列表的方式进行初始化
//普通成员变量也可以放在函数体里,但是本质其实已不是初始化,而是一种普通的运算操作-->赋值运算,效率也低
private:
int i;                                  // 普通成员变量
const int ci;                           // 常量成员变量
int &ri;                                // 引用成员变量
static int si;                          // 静态成员变量
//static int si2 = 100;                 // error: 只有静态常量成员变量,才可以这样初始化
static const int csi;                   // 静态常量成员变量
static const int csi2 = 100;            // 静态常量成员变量的初始化(Integral type)    (1)
static const double csd;                // 静态常量成员变量(non-Integral type)
//static const double csd2 = 99.9;      // error: 只有静态常量整型数据成员才可以在类中初始化
};

//注意下面三行:不能再带有static
int BClass::si = 0; // 静态成员变量的初始化(Integral type)
const int BClass::csi = 1; // 静态常量成员变量的初始化(Integral type)
const double BClass::csd = 99.9; // 静态常量成员变量的初始化(non-Integral type)

// 在初始化(1)中的csi2时,根据著名大师Stanley B.Lippman的说法下面这行是必须的。
// 但在VC2003中如果有下面一行将会产生错误,而在VC2005中,下面这行则可有可无,这个和编译器有关。
const int BClass::csi2;

int main()
{
BClass b;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐