找回密码
 立即注册
  • QQ空间
  • 回复
  • 收藏

C++ const 的使用

admin 2019-4-26 19:40 150人围观 C++相关

(给CPP开发者加星标,提升C/C++技能)


来源:鲸90830

https://www.cnblogs.com/whale90830/p/10542361.html

1) const 对象的一般形式


  • 类型名 const 对象名[(构造实参表列)];

  • const 类型名 对象名[(构造实参表列)];


注意:常对象必须要有初值(因为以后不能改值了)。

2) 限定作用:



定义为const的对象的所有数据成员的值都不能被修改。

凡出现调用非const的成员函数,将出现编译错误。但构造函数除外。

Time const t1(12,34,46); // t1是常对象
t1.set_Time(); // 编译错误PE, 非const成员函数
t2.show_Time(); // 错误,非const成员函数

3) mutable成员



对数据成员声明为mutable(易变的)时,即使是const对象,仍然可以修改该数据成员值。

常对象成员

1)常数据成员



使用const说明的数据成员称为常数据成员,其值是不能改变的。

如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。

class Time
{
    const int hour; // 声明hour为常数据成员
    Time(int h):hour(h){} // 通过参数初始化表对常数据成员hour初始化
};
class Time
{
    const int hour; // 声明hour为常数据成员
    Time(int h)
    {
        hour = h; // 错误
    }
};

例3.30 常数据成员举例。

#include <iostream.h>
class Date {
public:
    Date(int y,int m,int d);
    void showDate();
    const int &r;
private:
    const int year;
    const int month;
    const int day;
};
Date::Date(int y,int m,int d):year(y),month(m),day(d),r(year){ }
inline void Date::showDate()
{
    cout<<"r="<<r<<endl;
    cout<<year<<"."<<month<<"."<<day<<endl;
}
void main()
{
    Date date1(1998,4,28);
    date1.showDate();
}

2)常成员函数



在类中使用关键字const说明的函数为常成员函数。

常成员函数的说明格式如下:

类型说明符 函数名(参数表) const;

void show_Time( ) const; // 注意const的位置在函数名和括号之后
void Time::show_Time const
{
    cout << hour << minute << sec << endl;
}


注意:const是函数类型的一个组成部分,在声明函数和定义函数时都要有const关键字,在调用时不必加const。

例3.28 常引用作函数形参

#include<iostream.h>
int add(const int& i,const int& j);
void main()
{
    int a=20;
    int b=30;
    cout<<a<<"+"<<b<<"="<<add(a,b)<<endl;
}
int add(const int& i,const& j)
{
    return i+j;
}


如果将一个对象说明常对象,则通过该对象只能调用它的常成员函数,而不能调用普通成员函数。而且常成员函数也不能更新对象的数据成员。

例3.31 常成员函数的使用。

#include <iostream.h>
class Date {
public:
    Date(int y,int m,int d);
    void showDate();
    void showDate() const;
private:
    int year;
    int month;
    int day;
};
Date::Date(int y,int m,int d):year(y),month(m),day(d){ }
void Date::showDate()
{
    cout<<"ShowDate1:"<<endl;
    cout<<year<<"."<<month<<"."<<day<<endl;
}
void Date::showDate() const
{
    cout<<"ShowDate2:"<<endl;
    cout<<year<<"."<<month<<"."<<day<<endl;
}
void main()
{
    Date date1(1998,4,28);
    date1.showDate();
    const Date date2(2002,11,14);
    date2.showDate();
}


常成员函数只能引用本类中的数据成员,而不能修改它们,即成员数据不能作为语句的左值。
(注意:可以改mutable成员)

例 const对象及mutable成员

class Time{
public:
    Time()
    {
        hour = 0;
        minute = 0;
    }
    void set_Hour(int h) const { hour = h;}
    void set_Minute(int m) { minute = m; }
    void show_Time() const
    { cout<<hour <<":"<<minute << endl; }
private:
    mutable int hour;
    int minute;
};
int main()
{
    Time t1;
    t1.set_Hour(8);
    t1.set_Minute(8);
    t1.show_Time();
    Time const t2;
    t2.set_Hour(8);
    t2.set_Minute(8);
    t2.show_Time();
    return 0;
}

3)常成员的使用



  • a) 如果在一个类中,有些数据成员的值允许改变,另一些数据成员的值不允许改变,则可以将一部分数据成员声明为const,以保证其值不被改变,可以用非const的成员函数引用这些数据成员的值,并修改非const数据成员的值。

  • b) 如果要求所有的数据成员的值都不允许改变,则可以将所有的数据成员声明为const,或将对象声明为const(常对象),然后用const成员函数引用数据成员,这样起到“双保险”的作用,切实保证了数据成员不被修改。

  • c) 如果已定义了一个常对象,则只能调用其中的const成员函数,而不能调用非const成员函数(不论这些函数是否会修改对象中的数据)。如果需要访问对象中的数据成员,可将常对象中所有成员函数都声明为const成员函数,但应确保在函数中不修改对象中的数据成员。

指向常对象的指针变量

1)指向常对象的指针变量的一般形式



const 类型 *指针变量名

const char *pc; // pc 指向的 char 是const型的
*pa = 'a'; // 错误:pa 指向的目标不能改变
pa++; // 正确, pa 本身的值可以改变

Time t1;
const Time *pt;
*pt = t1; // 错误:pt指向的目标不能改变

2)关于指向常对象的指针变量的说明



  • a) 指向常对象(变量)的指针变量,不能通过它来改变所指向目标对象的值,但指针变量的值是可以改变的。

  • b) 如果被声明为常对象(变量),只能用指向常对象(变量)的指针变量指向它,而不能非const型指针变量去指向它。

const int a = 10, b = 20;
const int *pa = &a; // 正确
int *pb = &a; // 错误:非 const 型指针


  • c) 指向常对象(变量)的指针变量除了可以指向常对象(变量)外,还可以指向未被声明为const的对象(变量)。此时不能通过此指针变量改变该变量的值。

pa = &b; // 正确:也可指向非 const 型的变量
*pa = 30; // 错误:指向 const 型的指针不能改目标值


  • d) 指向常对象(变量)的指针变量可以指向const和非const型的对象(变量),而指向非const型变量的指针变量只能指向非const的对象(变量)。

const int *pa = &b; // 正确
int *pb = &a; // 错误



  • e) 如果函数的形参是指向非const型变量的指针,实参只能用指向非const变量的指针,而不能用指向const变量的指针,这样,在执行函数的过程中可以改变形参指针变量所指向的变量(也就是实参指针所指向的变量)的值。

void f(Time *pt);
Time *p1;
const Time*p2;
f(p1); // 正确
f(p2); // 错误


  • f) 如果函数形参是指向const型变量的指针,允许实参是指向const变量的指针,或指向非const变量的指针。

void g(const Time *pt)
Time *p1;
Const Time *p2;
f(p1); // 正确
f(p2); // 正确


  • g) 基本规则:希望在调用函数时对象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作实参(对象可以是const或非const型)。如果要求该对象不仅在调用函数过程中不被改变,而且要求它在程序执行过程中都不改变,则应把它定义为 const型

对象的常引用


在C++中,经常用常指针和常引用作函数参数。这样既能保证数据安全,使数据不能被随意修改,在调用函数时又不必建立实参的拷贝,可以提高程序运行效率。

例 对象的常引用。

class Time{
public:
    Time(int,int,int);
    int hour;
    int minute;
    int sec;
};
Time::Time(int h,int m,int s)
{
    hour = h;
    minute = m;
    sec = s;
}
void fun1(Time &t) // t 是对象引用
{ t.hour = 18; }
void fun2(const Time &t) // t 为常引用
{ t.hour = 18; // 错误 }
int main( )
{
    void fun1(&);
    void fun2(const Time &);
    Time t1(10,13,56);
    fun(t1);
    cout<<t1.hour<<endl;
    return 0;
}
例3.29 非常对象和常对象的比较。

#include<iostream.h>
class Sample {
public:
    int m;
    Sample(int i,int j){ m=i; n=j;}
    void setvalue(int i){ n=i; }
    void disply()
    {
        cout<<"m="<<m<<endl;
        cout<<"n="<<n<<endl;
    }
private:
    int n;
};
void main()
{
    Sample a(10,20); //若为:const Sample a(10,20);
    a.setvalue(40);//不能修改常对象的数据成员
    a.m=30; //不能修改常对象的数据成员
    a.disply();//常对象不能调用普通成员函数
}

const型数据的小结Time const t = Time(1,2,3);

const Time t = Time(1,2,3);
const int a = 10;
int const a = 10;


  • t是常对象,其成员值在任何情况下都不能被改变。

  • a 是常变量,其值不能被改变

void Time::fun() const;

fun 是Time类的常成员函数,可以调用该函数,但不能修改本类中的数据成员(非mutable)

Time * const pt;
int * const pa;


  • pt 是指向Time对象的常指针,

  • pa 是指向整数的常指针。指针值不能改变。

const Time *pt;
const int *pa;


  • pt是指向Time类常对象的指针,

  • pa是指向常整数的指针,不能通过指针来改变指向的对象(值)



推荐阅读

(点击标题可跳转阅读)

C++ 对象数组与对象指针

聊聊 C++ 左值,纯右值与将亡值

C++20 要来了!


看完本文有帮助?请分享给更多人

关注「CPP开发者」加星标,提升C/C++技能



喜欢就点一下「好看」呗~

----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:CPP开发者,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

yafeilinux和他的朋友们微信公众号二维码

微信公众号

专注于Qt嵌入式Linux开发等。扫一扫立即关注。

Qt开源社区官方QQ群二维码

QQ交流群

欢迎加入QQ群大家庭,一起讨论学习!

我有话说......