提高程序的健壮性和效率(const、static、try{}catch(){})

本文详细介绍了C++中const关键字的用法,包括修饰基本数据类型、指针和函数参数、返回值,以及const成员函数的作用。同时,解释了static如何影响局部变量、全局变量和函数的可见性和生命周期。最后提到了异常处理的try-catch结构在程序健壮性中的重要性。
摘要由CSDN通过智能技术生成

一、const

1. const修饰基本数据类型

1.1 用const修饰基本数据类型

1.1.1 const修饰一般常量及数组
  • 对于这些基本的数据类型,修饰符const可以用在类型说明符前,也可以用在类型说明符后,其结果是一样的
int const a = 100;
const int a = 100; //与上面等价
int const arr [3] = {1,2,3};
const int arr [3] = {1,2,3};//与上面等价
1.1.2 const修饰指针(*)

以下的区别是指针能否指向别的变量,指向的数据能否被改变

char *p = "hello";     // 非const指针,
                       // 非const数据
                       
const char *p = "hello";  // 非const指针,
                          // const数据

char * const p = "hello";   // const指针,
                            // 非const数据

const char * const p = "hello";  // const指针,
                                 // const数据
常量指针

当为常量指针时,不可以通过修改所指向的变量的值,但是指针可以指向别的变量。

int a = 5;
const int *p =&a;
*p = 20;   //error  不可以通过修改所指向的变量的值

int b =20;
p = &b; //right  指针可以指向别的变量
指向常量的指针(指针常量)

当为指针常量时,指针常量的值不可以修改,就是不能指向别的变量,但是可以通过指针修改它所指向的变量的值。

int a = 5;
int *const p = &a;
*p = 20;     //right 可以修改所指向变量的值

int b = 10;
p = &b;      //error 不可以指向别的变量

上述的常量指针和指向常量的指针可以总结为:左定值,右定向,const修饰不变量(左和右相对于*)

以下对比无const修饰和都有const修饰情况

int* p1 = &a;   
*p1 = 100;		//可以修改值 
p1 = &b;		//也可以修改方向

------------------------------------------------------------
const int* const p5 = &a;//指针前有指针后也有 均不可以改变

2. const修饰函数

const更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体

2.1 用const修饰函数的参数

const只能修饰输入参数,不能修改输出参数

  • 如果输入参数采用“指针传递”,那么加const修饰可以防止意外地改动该指针指向的内容,起到保护作用,【适用:左定值】

  • 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰。【enum类型的数据不用引用】

  • 对于非内部数据类型的参数而言,应该将“值传递”的方式改为“const引用传递”,例如结构体

    • 例如:void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间,浪费内存。而改为“引用传递”,”仅借用一下参数的别名而已,不需要产生临时对象。但“引用传递”有可能改变参数a,加const修饰即可。值得注意的是,是否应将void Func(int x) 改写为void Func(const int &x),以提高效率?完全没有必要,既达不到提高效率的目的,又降低了函数的可理解性。因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当
    • 传递一个指向对象的指针与引用方式效果相同,但是引用比指针更加好用,可以阅读博文C++ 引用详解(引用的特点,引用与指针的区别,引用的其他使用)了解引用的特点

2.2 用const修饰函数的返回值

  • 如果给以“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同类型指针。
const char *str = GetString();
  • 如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值。即如果返回值是结构体,加const则有意义,如果返回是基本数据类型,加const返回则没有意义
例如不要把函数int GetInt(void) 写成const int GetInt(void)。

同理不要把函数A GetA(void) 写成const A GetA(void),其中A为用户自定义的数据类型。

如果返回值不是内部数据类型,将函数A GetA(void) 改写为const A & GetA(void)的确能提高效率。
但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,
否则程序会出错。
  • 函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。
class A
{A & operate = (const A &other); // 赋值函数
};
A a, b, c; // a, b, c 为A的对象…
a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法
如果将赋值函数的返回值加const修饰,那么该返回值的内容不允许被改动。
上例中,语句 a = b = c仍然正确,但是语句 (a = b) = c 则是非法的。

2.3 用const修饰成员函数的定义

  • 任何不会修改数据成员的函数都应该声明为const类型,相当于这个函数是个只读函数。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性。

  • const成员函数只能调用const成员函数,不能调用非const成员函数,因为非const成员函数可能改变对象的数据成员

  • const只能修饰成员函数,普通函数不可以加const

  • 在类中被const 声明的函数只能访问const 函数,而非const 函数可以访问任意成员函数,包括const 成员函数。

  • 加上mutable修饰符的数据成员在任何情况下通过任何手段都可以进行修改,所以在const函数也是可以进行修改的

  • 如果函数名、参数、返回值都相同的const成员函数和非const成员函数是可以构成重载,那么const对象调用const成员函数,非const对象默认调用非const的成员函数

class Stack
{
public:
	void Push(int elem);
	int Pop(void);
	int GetCount(void) const; // const成员函数

private:
	int m_num;
	int m_data[100];
};

int Stack::GetCount(void) const //GetCount仅仅只用作计数,不修改成员变量
{
	++ m_num; // 编译错误,企图修改数据成员m_num
	Pop(); // 编译错误,企图调用非const函数
	return m_num;
}
  • const修饰的成员函数:实际上修饰的是this指针指向空间的内容不可被修改
  • 有了const修饰的成员函数,其this指针类型:const Date* const (左定值,右定向)
  • 而普通的成员函数:可以修改成员变量 ,其this指针类型:Date* const

二、static

  • 1)用static修饰局部变量:

    • 使得局部变量由自动存储期变为静态存储期,生存期变得和全局变量一样,直到程序结束才释放,
    • 但是并不是将该变量声明为全局变量,其他函数内也无法使用,也就是说改变了的存储位置,生存期发生了改变,但是作用域并没有改变,任然是局部变量作用域
    • 初始化:未经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化);
  • 2)用static修饰全局变量:

    • 使其只在本文件内部有效,而其他文件不可连接或引用该变量。(注意:普通全局变量可以在其他.c文件中使用,只需要extern关键字,在链接的时候会找到该变量的地址)
    • 还是静态存储区,在整个程序运行期间一直存在。
    • 初始化:未经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化);
  • 3)用static修饰函数:

    • 在定义函数的时候,返回值类型前面加 static 修饰。这样的函数 被称为静态函数。
    • 对函数的链接方式产生影响,使得函数只在本文件内部有效,对其他文件是不可见的(这一点在大工程中很重要很重要,函数的定义和声明在默认情况下都是extern的)。
    • 使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机制。
    • 注意:不要在头文件中声明static的全局函数,不要在cpp内声明非static的全局函数,如果你要在多个cpp中复用该函数,就把它的声明提到头文件里去,否则cpp内部声明需加上static修饰;
  • 4)类的静态成员

    • 在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用
  • 5)类的静态成员函数

    • 静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
    • 在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员(这点非常重要)。如果静态成员函数中要引用非静态成员时,可通过对象来引用。从中可看出,调用静态成员函数使用如下格式:<类名>::<静态成员函数名>(<参数表>);

声明时加上static修饰,实现的时候也不需要static 的修饰,因为static是声明性关键字;类的静态函数是在该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员,不需要类的实例即可调用;实际上,它就是增加了类的访问权限的全局函数:

//类的静态函数
class A
{
	private:
		static void func(int value);
};

//实现
void A::fun(int);

三、try{}catch(){}


参考博文:

C++基础——const成员函数

C、C++中使用const提高程序的健壮性和效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值