C++ const解说 转载 C++开发 2022年7月31日 10:59 夏至未至 1158 当前内容 7005 字,在路上,马上到,马上到 ### 目录 [TOC] ### 使用场景 #### 修饰变量 它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。 const int a; // a 代表一个常整型数 int const a; // a 代表一个常整型数 const int *a; // a 代表一个指向常整型数的指针,即a的值是可变的,但是*a是不能变的,函数的一些形参经常会用到 int * const a; // a 代表一个常指针,即a的值是不可变的,但是*a是可变的 int const * a const; // a代表的是一个指向常整型数的常指针 主要看const修饰的是什么? 1. const + 类型: 说明const修饰的是类型,想让类型为常量,也就是这个类型的值为常量。 例如const int *a; 本来是定义一个指针变量,指针变量所指向的值为int类型。const修饰int 类型,那也就是说这个int 类型的值为常量,也就是说指针指向的值为常量。 2、const + 变量 说明const修改的变量,想让这个变量为常量。 例如int *const a; 本来是定义一个指针变量,指针变量所指向的值为int 类型。const修饰变量,那就是说这个指针变量为常量,不可变。指针所指向的int类型的值是可变的。 3、const 与 指针 int a = 20; const int * p = &a; 上面定义了一个常指针,指向的数据 a 是不变的。即不能修改 *p 的值。 *p += 1; //INVALID coin >> *p; //INVALID 尝试修改 `*p` 的值,是不被允许的,因为p指向的为const 的值。但是,如果修改a是可以的,因为a是普通变量。 a = 30; //VALID const int a = 20; int *p = &a; //INVALID 上面定义一个可变的指针,指向一个const 的值,这个是不允许的。可以想下,如果这里允许,那样可以修改a 的值,`*p = 30;` 这样a 的const状态就荒谬了。C++禁止将const 地址赋给非const 的指针。如果非要这样做,可以通过const_cast 强制转换。 这里修改为: const int* p = &a; //VALID 如果将指针指向指针,则情况将更复杂一点。上面讲到如果是一级间接关系,可以将非const的指针赋给const的指针。例如, int a = 10; int *p = &a; cont int *pt = p; 上面的操作都是允许的,只不过需要注意的是,*p 是可以修改的,但是*pt 就不能修改。 然而,进入二级间接关系时,与一级间接关系一样将const 和非const混合的指针赋值方式将不再安全。例如, const int **p2; int *p1; const int a = 20; p2 = &p1; //这里是不被允许的,编译的时候会报错 *p2 = &a; *p1 = 10; 上面将非const 的指针p1的地址赋值给const 指针p2,因此可以使用p1来修改const数据。因此,仅当只有一层间接关系(如指针指向基本数据类型)时,才可以将非const 地址或指针赋给const 指针。 4、尽可能的使用const: 将指针参数声明为指向常量数据的指针有两个理由: ● 这样可以避免由于无意间修改数据而导致的编程错误; ● 使用const 使得函数能够处理const 和非const 实参,否则只能接受非const 数据。 例如,有个常量数据array定义如下: const int array [] = {1, 2, 3, 4, 5}; 有个函数func定义如下: void func(int array[], int n) { ... } 将上面常量数组作为参数传入,是不允许的,需要将参数改为const。 #### 修饰函数 1、const 修饰函数参数 如果函数作为输出用,不论是什么数据类型,也不论采用指针传递还是引用传递,都不能加const 修饰,否则参数会失去输出功能。 const 只能修饰输入作用的参数。 如果输入参数为指针,加上const 之后起到保护指针意外修改的作用。 例如, void StringCopy(char* strDest, const char* strSource); 这里strSource 加上const 修饰,就是为了防止strSource 会被意外的修改。实参中指针指向一段内存地址,调用函数之后,函数会产生一个临时指针变量,这个变量的地址肯定跟实参的指针地址不一样,但是这两指针指向的内存是同一块。形参加上const 修饰之后,保护了这一块内存地址不被修改,如果刻意修改这一块内存,编译器会报错。 如果输入参数为引用,加上const 之后不但起到了保护作用,也提高了程序效率。 例如, void func(A a); //这里的A类型为用户定义的类型 这个函数在调用的时候会生成一个临时对象,而且会调用拷贝构造函数,函数结束还要析构。如果改成引用void func(A &a); 只是相当于实参的一个别名,不会产生临时变量。所以,如果是自定义类型,建议用引用作为函数形参。 但是,即使用引用,如果只是作为输入用,最好加上const 修饰,这样就不会改变实参的值,如果刻意修改,编译器会报错。所以,函数最后改成void func(const A& a); 当然,不是所有的数据类型都需要用应用,例如, void func(int x); 对于内部类型的参数,不存在构造、析构的过程,产生临时变量、值的复制过程很快,无需用引用。 2、const 修饰函数返回值 如果是值传递,没有必要将返回值用const 修饰,例如, const int func(); 函数的返回值为一个int 类型的值,这个只是个临时的值,没有必要用const 修饰,最终这个值会复制给接受它的变量。 如果返回值为引用,同上面形参,都可以提高效率。但是一般返回引用的地方并不是很多,一般会出现在类的赋值函数中。而且,用const 修饰返回值为引用类型的更少。 如果返回值为指针,加上const修饰之后,同样的内容是不能修改的。不过有一点需要注意,接受的变量也必须是const 修饰。例如, const char* func(); char* str = func(); 上面这样调用是不对的,需要将变量str 用const修饰,改为: const char* str = func(); 3、const 修饰成员函数 const 修饰的成员函数为了保护成员变量,要求const 函数不能修改成员变量,否则编译会报错。 声明的时候const放在函数最后,例如, class MyClass { public: void func(int x) const; }; const 函数的几个规则: 1)const 对象只能访问const 成员函数,非const 的对象可以访问任何成员函数,包括const 成员函数。 2)如果函数名、参数、返回值都相同的const成员函数和非const成员函数是可以构成重载,那么const对象调用const成员函数,非const对象默认调用非const的成员函数。 3)const成员函数可以访问所有成员变量,但是只能访问const的成员函数。 4)非const成员函数,可以访问任何成员,包括const成员成员函数。 5)const成员函数不能修改任何的成员变量,除非变量用mutable修饰。 这一点可以理解为,在const的成员函数中成员变量都变成const属性,无法再次修改。如果函数的返回类型为此成员变量的引用,那必须也要加上const修饰。例如, class MyClass { public: int & func() const { return value; } private: int value; }; value为成员变量,func函数为const成员函数,如果要返回value的引用,这里的func函数返回值必须要加上const,改为, const int& func() const { return value; } 当然,还有其他修改方法: ● 把int value 改成mutable int value。mutable修饰的变量使之在const函数中可以被改变的 ● return value 改成。 return const_cast(value)。const_cast去掉了const性质。 ● 把引用去掉,写成返回值类型的。 ● 把函数后面的const去掉。 ### 实例说明 #include "test.h" class Test9 { public: Test9() : vTest1(1), vTest2(1) { cout << "Test9 constructor.\n"; } ~Test9() { cout << "Test9 destructor.\n"; } void test1(); void test2() const; void funcForTest9(const int *); //int &test6()const { return vTest1; }//const成员函数中的成员变量变为const 修饰,返回值必须要要const private: void test3() { cout << "Test9 test3()\n"; } void test4() const { cout << "Test9 test4()\n"; } void test5() { cout << "Test9 test5().\n"; } void test5() const { cout << "Test9 test5()const.\n"; } void test6(); int vTest1; const int vTest2; }; void Test9::test1() { cout << "Test9 test1.\n"; cout << "value of vTest1 is " << vTest1 << endl; cout << "value of vTest2 is " << vTest2 << endl; vTest1 = 10;//普通成员函数是可以修改成员变量 //const 和非const的成员函数都可以访问 test3(); test4(); test5();//调用的是非const的成员函数 /*cout << endl; test6();*/ } void Test9::test2() const{ cout << "Test9 test2.\n"; cout << "value of vTest1 is " << vTest1 << endl; cout << "value of vTest2 is " << vTest2 << endl; //vTest1 = 10;//const成员函数不能修改成员变量 //test3();//const成员函数只能访问const函数,不能访问非const的成员函数 test4(); test5();//调用的是const的成员函数 } void Test9::funcForTest9(const int* x) {//这里参数表示x指向的值不能修改 cout << "address of pointer x is " << &x << endl; cout << "pointer x is " << x << endl;//这里跟实参是一个地址 cout << "value of pointer x is " << *x << endl;//这里是实参的值 int a = 20; cout << "\naddress of a is " << &a << endl; //*x = a; //编译器会报错,左值必须是可修改的 x = &a;//代表着之前的*x不能修改,x可以修改 cout << "address of pointer x is " << &x << endl; cout << "pointer x is " << x << endl; cout << "value of pointer x is " << *x << endl; } void Test9::test6() { const int **p2; cout << "address of p2 is " << &p2 << endl; cout << "value of p2 is " << p2 << endl; int *p1; cout << "address of p1 is " << &p1 << endl; cout << "value of p1 is " << p1 << endl; const int a = 10; cout << "address of a is " << &a << endl; cout << "value of a is " << a << endl; //p2 = &p1; //二级间接关系,是不允许非const 指针赋给const指针 cout << "address of p2 is " << &p2 << endl; cout << "value of p2 is " << p2 << endl; *p2 = &a; cout << "address of p2 is " << &p2 << endl; cout << "value of p2 is " << p2 << endl; cout << "value of *p2 is " << *p2 << endl; cout << "address of p1 is " << &p1 << endl; cout << "value of p1 is " << p1 << endl; *p1 = 10; } void Test::test9() {//这里是给main调用的入口函数 int x = 10; cout << "address of x is " << &x << endl; int *p = &x; cout << "address of pointer p is " << &p << endl; cout << "pointer p is " << p << endl; cout << "value of pointer p is " << *p << endl; cout << endl; Test9 obj; obj.funcForTest9(p); cout << endl; obj.test1(); cout << endl; const Test9 obj_1; //obj_1.test1();//const对象,不能访问非const成员函数。 cout << endl; obj_1.test2(); //obj_1.vTest1 = 10;//不可以访问const 对象的任何成员 } 原文链接:https://blog.csdn.net/shift_wwx/article/details/79020617 本文标题: C++ const解说 本文作者: 夏至未至 发布时间: 2022年7月31日 10:59 最近更新: 2022年7月31日 10:59 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 C++开发(12) const(1) 上一个 C++Builder 6.0 开发扩展工具推荐 下一个 简单的扫码支付页面(源码) 当前文章评论暂未开放,请移步至留言处留言。