-σσ【605892】备Q用【8099468】精准带计划,一对一指导【不限玩法实力把把结】

  1什么是const?
  
  (const类型)常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(但可以偷梁换柱进行更新)
  
  2为什么引入const?
  
  const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。
  
  3主要作用
  
  (1)可以定义const常量,具有不可变性。
  
  例如:const int Max=100; int Array[Max];
  
  (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。
  
  例如: void f(const int i) { .........} 编译器就会知道i是一个常量,不允许修改;
  
  (3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变!
  
  如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可!
  
  (4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。还是上面的例子,如果在函数体内修改了i,编译器就会报错;
  
  例如: void f(const int i) { i=10;//error! }
  
  (5)可以节省空间,避免不必要的内存分配。例如:
  
  #define PI 3.14159 //常量宏
  
  const double Pi=3.14159; //此时并未将Pi放入RAM中 ......
  
  double i=Pi; //此时为Pi分配内存,以后不再分配!
  
  double I=PI; //编译期间进行宏替换,分配内存
  
  double j=Pi; //没有内存分配
  
  double J=PI; //再进行宏替换,又一次分配内存!
  
  const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
  
  (6)提高了效率。
  
  编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
  
  4 const怎样限定内容
  
  限定变量时:
  
  例:下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?
  
  typedef char * pStr;
  
  char string[4] = "bbc";
  
  const char *p1 = string; //1式
  
  const pStr p2 = string; //2式
  
  p1++;
  
  p2++;
  
  答案与分析:
  
  问题出在p2++上。
  
  const使用的基本形式: const type m;限定m不可变。替换基本形式中的m为1式中的*p1,替换后const char *p1;限定*p1不可变,当然p1是可变的,因此问题中p1++是对的。替换基本形式中的type为2式中的pStr,替换后const pStr m;限定m不可变,题中的pStr就是一种新类型,因此问题中p2不可[1]变,p2++是错误的。
  
  const只修饰其后的变量,至于const放在类型前还是类型后并没有区别。如:const int a和int const a都是修饰a为const。一个简单的判断方法:指针运算符*,是从右到左,那么如:char const * pContent,可以理解为char const (* pContent),即* pContent为const,而pContent则是可变的。
  
  int const * p1,p2;
  
  p2是const;(*p1)是一整体,因此(*p1)是const,但p1是可变的。int * p1,p2只代表p1是指向整型的指针,要表示p1、p2都是指针是需写成int * p1,* p2。所以无论是* const p1,p2还是const * p1,p2,里面的*都是属于p1的。
  
  int const * const p1,p2;
  
  p2是const,是前一个const修饰的,*p1也被前一个const修饰,而p1被后一个const修饰。
  
  int * const p1,p2;
  
  p1是const,(* const p1)是整体,所以const不修饰p2。
  
  指针指向及其指向变量的值的变化
  
  const在*的左边,则指针指向的变量的值不可变;在*的右边,则指针的指向不可变。简记为"左定值,右定向"。
  
  1)指针指向的变量的值不能变,指向可变
  
  int x = 1;
  
  int y = 2;
  
  const int* px = &x;
  
  int const* px = &x; //这两句表达式一样效果
  
  px = &y; //正确,允许改变指向
  
  *px = 3; //错误,不允许改变指针指向的变量的值
  
  2)指针指向的变量的值可以改变,指向不可变
  
  int x = 1;
  
  int y = 2;
  
  int* const px = &x;
  
  px = &y; //错误,不允许改变指针指向
  
  *px = 3; //正确,允许改变指针指向的变量的值
  
  3)指针指向的变量的值不可变,指向不可变
  
  int x = 1;
  
  int y = 2;
  
  const int* const px = &x;
  
  int const* const px = &x;
  
  px = &y; //错误,不允许改变指针指向
  
  *px = 3; //错误,不允许改变指针指向的变量的值
  
  以 const 声明的变量的指针只能分配给同时声明为 const的指针。
  
  // constant_values4.cpp
  
  #include <stdio.h>
  
  int main() {
  
  const char *mybuf = "test";
  
  char *yourbuf = "test2";
  
  printf_s("%s\n", mybuf);
  
  const char *bptr = mybuf; // Pointer to constant data
  
  printf_s("%s\n", bptr);
  
  // *bptr = ‘a‘; // Error
  
  }
  
  不能声明具有 const 关键字的构造函数或析构函数。
  
  限定成员函数时:
  
  声明带有 const 关键字的成员函数指定,函数是 "只读"函数,在它被调用的时候不会修改对象。 一个常数成员函数不能修改任何非静态数据成员或调用不是常数的任何成员函数。若要声明常数成员函数,请在参数列表的右括号后放置const关键字,把const关键字放在函数的参数表和函数体之间。有人可能会问:为什么不将const放在函数声明前呢?因为这样做意味着函数的返回值是常量,意义完全不同。 声明和定义中均要求该 const 关键字。
  
  // constant_member_function.cpp
  
  class Date
  
  {
  
  public:
  
  Date( int mn, int dy, int yr );
  
  int getMonth() const; // A read-only function
  
  void setMonth( int mn ); // A write function; can‘t be const
  
  private:
  
  int month;
  
  };
  
  int Date::getMonth() const
  
  {
  
  return month; // Doesn‘t modify anything
  
  }
  
  void Date::setMonth( int mn )
  
  {
  
  month = mn; // Modifies data member
  
  }
  
  int main()
  
  {
  
  Date MyDate( 7, 4, 1998 );
  
  const Date BirthDate( 1, 18, 1953 );
  
  MyDate.setMonth( 4 ); // Okay
  
  BirthDate.getMonth(); // Okay
  
  BirthDate.setMonth( 4 ); // C2662 Error
  
  }
  
  限定函数的传递值参数:
  
  void function(const int Var); //传递过来的参数在函数内不可以改变.
  
  限定函数返回值型.
  
  const int function(); //此时const无意义
  
  const myclassname function(); //函数返回自定义类型myclassname.
  
  限定函数类型.
  
  void function()const; //常成员函数, 常成员函数是不能改变成员变量值的函数。
  
  非常量成员函数不能被常量成员对象调用,因为它可能企图修改常量的数据成员. 任何不修改成员数据的函数都应该声明为const函数,这样有助于提高程序的可读性和可靠性。
  
  void AddElem(const int);
  
  bool Set::Member (const int elem) const;
  
  const Set s;
  
  s.AddElem(10); // 非法: AddElem不是常量成员函数
  
  s.Member(10); // 正确
  
  但构造函数和析构函数对这个规则例外,它们从不定义为常量成员,但可被常量对象调用(被自动调用)。它们也能给常量的数据成员赋值,除非数据成员本身是常量。
  
  const成员函数和const对象
  
  实际上,const成员函数还有另外一项作用,即常量对象相关。对于内置的数据类型,我们可以定义它们的常量,用户自定义的类也一样,可以定义它们的常量对象。例如,定义一个整型常量的方法为:
  
  const int i=1 ;
  
  同样,也可以定义常量对象,假定有一个类classA,定义该类的常量对象的方法为:
  
  const classA a(2);
  
  这里,a是类classA的一个const对象,"2"传给它的构造函数参数。const对象的数据成员在对象寿命期内不能改变。但是,如何保证该类的数据成员不被改变呢?
  
  为了确保const对象的数据成员不会被改变,在C++中,const对象只能调用const成员函数。如果一个成员函数实际上没有对数据成员作任何形式的修改,但是它没有被const关键字限定的,也不能被常量对象调用。下面通过一个例子来说明这个问题:
  
  class C
  
  {
  
  int X;
  
  public:
  
  int GetX()
  
  {
  
  return X;
  
  }
  
  void SetX(int X)
  
  {
  
  this->X = X;
  
  }
  
  };
  
  void main()
  
  {
  
  const C constC;
  
  cout<<constC.GetX();
  
  }
  
  如果我们编译上面的程序代码,编译器会出现错误提示:constC是个常量对象,它只能调用const成员函数。虽然GetX( )函数实际上并没有改变数据成员X,由于没有const关键字限定,所以仍旧不能被constC对象调用。如果我们将上述代码中:
  
  int GetX()
  
  改写成:
  
  int GetX()const
  
  再重新编译,就没有问题了。

猜你喜欢

转载自www.cnblogs.com/zhenhua1618/p/12729362.html