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

文章目录

  • 一、const
    • 1. const修饰基本数据类型
      • 1.1 用const修饰基本数据类型
        • 1.1.1 const修饰一般常量及数组
        • 1.1.2 const修饰指针(*)
          • 常量指针
          • 指向常量的指针(指针常量)
    • 2. const修饰函数
      • 2.1 用const修饰函数的参数
      • 2.2 用const修饰函数的返回值
      • 2.3 用const修饰成员函数的定义
  • 二、static
  • 三、try{}catch(){}

一、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

  • 在一般的函数前面加上static作用是:

    • 加了static后表示该函数失去了全局可见性,只在该函数所在的文件作用域内可见
      当函数声明为static以后,编译器在该目标编译单元内只含有该函数的入口地址,没有函数名,其它编译单元便不能通过该函数名来调用该函数。
  • 在类的成员函数前面加上static作用是:

    • 成员函数是属于类的,而非对象的,也就是所有该类的对象共同拥有这一个成员函数,而不是普通的每个对象各自拥有一个成员函数
  • 声明时加上static修饰,实现的时候也不需要static 的修饰,因为static是声明性关键字;类的静态函数是在该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员,不需要类的实例即可调用;实际上,它就是增加了类的访问权限的全局函数:

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

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

三、try{}catch(){}

  • 阅读:C++57个入门知识点_57 异常处理(为了程序健壮性,使用try{}catch(){}将代码包裹,出现异常时可以被程序接到,而不会造成程序阻塞或崩溃;需要在VS中打开设置;exception类)

参考博文:

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

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

你可能感兴趣的:(算法,数据结构,c++)