八、Constants(常量)
八、Constants(常量)
总览
const
是C++引入的关键字,用来明确哪些值是不可修改 的,从而增强代码的安全性和可读性 。const
出现的最初动机似乎是为了取代预处理器中的#define
来进行值替换。现在它已经被广泛用于指针、函数参数、返回类型、类对象和成员函数中。
- 值替代
- 指针
- 函数参数与返回值
- 类成员与成员函数
8.1 值代替(Value substitution)
-
预处理器中的
#define
仅仅是文本替换 ,并没有类型检查 的概念或机制。 -
在C++中可以通过使用
const
常量来避免这些问题。示例
#define BUFSIZE 100 //宏,从#define 到 #undef,BUFSIZE 是替换文本 const int bufsize = 100; //一个语句,bufsize 有 int 类型,默认是内部连接
内部连接是指,具有内部连接的变量或函数,只能在它定义的那个源文件中访问,其他文件访问不到它。
-
Constant 必须被初始化,且不能被修改赋值
const int model = 90; //model 是常量 const int v[] = {1,2,3,4}; // v[i] 是常量 const int x; //error:未初始化model = 90; //error:不能修改常量 v[2]++; // error:不能修改常量数组元素
8.2 指针(Pointer)
cosnt 修饰指针有三种形式
-
指向常量的指针(pointer to const)
const char s = '9'; const char* pc = &s;//内容不能变(指针指向的地址的内容不能改),指针可变(指针的指向什么地址可变) *pc = 'i'; // error:指针指向的地址的内容不可以变 char d = '7'; pc = &d; // ok:指针可变
-
常量指针(const pointer)
char s = '9'; char* const p = &s;//指针不能变,内容可变 *p = 'i'; // ok:内容可变 char d = '7'; pc = &d; // error:指针不可变
-
指向常量的常量指针(const pointer to const)
char s = '9'; const char* const p = &s;//指针不能变,内容也不可变 *p = 'i'; // error:内容不可变 char d = '7'; pc = &d; // error:指针不可变
赋值规则:常量地址只能赋给const
指针
const float f1 = 5.0;
float f2 = 0.0;
const flaot* p = &f1; // ok
float* p1 = &f1; //error
float* const p2 = &f1; //error
float* p4 = &f2; //ok
float* const p5 = &f2; // ok
const float* const p6 = &f2; //ok
变量可以变常量,常量不可以变变量
8.3 函数参数与返回值(Function argument2 & return values)
概述
- 如果你是通过地址传递和返回 ,
const
表示你承诺不会改变该地址所指向的内容。 - 如果你是通过值传递对象 , 指定
cosnt
对于调用者来说是没有意义的。 - 如果你是以
const
方式按值返回一个类对象 ,这意味着返回值不能作为左值使用(即不能被赋值或修改)。
//C08:ConstPointer.cpp
//Constant pointer
void t(int* p){}
void u(const int* cip){*cip = 2;//errorint i = *cip;//OKint* ip2 = cip;//error
}
const char* v(){…………}
const int* const w(){…………}void main()
{int x = 0;int* ip = &x;const int* cip = &x;t(ip);//okt(cip);//error:const不可变非constu(ip);//oku(cip);//okchar* cp = v(); //errorconst char* ccp = v();//okint* ip2 = w();//errorconst int* const ccip = w();const int* cip2 = w();//ok*w() = 1;//error
}
临时变量
- 有时,在计算一个表达式的过程中,编译器必须创建临时对象(temporary objects)。
- 编译器会自动将所有临时对象设为
cosnt
。
示例
#include <iostream>
using namespace std;
class Date
{int year.month,day;
public:Date(){year = month = day = 0;cout << "Default constructor called." << endl;}Date(int y,int m,int d){year = y;month = m;day = d;cout << "Constructor called." << day << endl;}~Date(){cout << "Destructor called." << day << endl;}void Print(){cout << year << "." << month << "." << day << endl;}
};void main(){//initializationDate dates[3] = {Date(2025,4,26),Date(2025,4,27)};for (int i = 0;i<3;i++){date[i].Print();}dates[2] = Date(2003,9,22);//assignmentfor (i = 0;i < 3 ; i++){dates[i].Print();}
}
输出
传递和返回地址
-
如果我们传递或返回一个地址(指针或引用),调用者程序员就有可能通过这个地址修改原始值 。
-
因此我们将这个指针或引用声明为
const
,就可以防止这种修改的发生 。//不会修改d所引用的对象 void f(const double& d){//………… }
8.4 类与cosnt
静态数据成员(Static Data Members)
-
类的所有对象都共享一个
static
,static
数据成员是所有类共享的,唯一的。 -
一定要初始化
- 一定要在类外初始化
- 初始化的时候不能再加个
static
关键字 - 必须使用类名限定符(:😃
class Myclass{static int obj;//静态数据成员 }; int Myclass::obj = 8;//初始化
cosnt数据成员
-
const
数据成员无法被修改 -
const
和引用
数据成员必须在构造函数的成员初始化列表 (member initializer list)中进行初始化。 -
因为
const
和引用
(references) 成员必须被初始化,所以包含cosnt
或引用
成员的类无法使用默认构造函数进行构造。class A{ public:A(int i );void Print(); private:cosnt int a;//const data memberstatic const int b;//statci constconst int& r;//const refrence }; const int A::b = 10; A::A(int i):a(i),r(a){…………}
a(i),r(a)
就是初始化列表,a(i)
类似a = i
。
const 成员函数
模板: type function-name(arguments) const;
class Date{
public:Date(int i,int j,int k){y = i;j = m;d = k;}int year() const;int month() const{ return m;}int day(){return d;}
private:int y,m,d;
};
-
const
成员函数不会修改任何成员变量int Date::year() const{return y++;//error:试图修改成员的值 }
-
函数定义在外时,也需要
const
。int Date::year() const{return y; }
定义的时候,
const
不要落下
const对象
- 对于非
const
对象,可以调用const
成员和非const
成员。 - 对于
const
对象,只能调用const
成员。
示例
#include <iostream>
using namespace std;
class Date{
public:Date(int i,int j,int k){y = i;j = m;d = k;}int year() const;int month() const{ return m;}int day(){return d;}
private:int y,m,d;
};void main(){Date A(2003,10,1); //non-const objectcout << A.year() << endl;cont << A.day() << endl;const Date B(2009,9,8); //const objectcout << B.year() << endl;cout << B.day() << endl;//error
}
mutable 成员
-
存储说明符
mutable
指定某个成员变量应当以允许修改的方式被存储。 -
即使一个成员函数是
const
,只要成员变量被声明为mutable
,这个成员变量仍然可以在cosnt
函数中被修改。#include <iostream> using namespace std; class Date{ public:Date(int i,int j,int k){y = i;j = m;d = k;}int year() const{return ++y;};//okint month() const{ return m;}int day(){return d;} private:mutable int y;int m,d; };void main(){Date A(2003,10,10); //declare a obejctcout << A.year() << endl;//okcout << A.day() << endl; }
8.5 总结
const
提供更强的类型检查与代码安全- 推荐使用
const
代替#define
宏定义 - 可用于值、指针、函数参数/返回值、类成员
const
成员函数保护成员变量不被更改const
对象只能访问const
成员函数