C++中const的用法【03】----类

前面介绍了const 在常量与指针和const 在函数中的用法,虽然放在不同的位置会有不同的用法,但归根结底, const 的思想都没有变----那就是用来修饰一个不能被改变的量。

然而,const 在类中的含义有所不同。

下面我们来介绍const在类中的具体情况。

const 不仅被用来修饰类的成员,还可以在类外,是整个实例都作为const ,但类中难免有修改数据成员的函数,因此为了保持统一,C++引进了const 成员函数,const 成员函数只能被const 对象调用。


1. 类中的const

有时,我们可能遇到如下情况,创建了一个类,并且希望它的所有实例都有一个统一且确定的值。对于我们来说,最合乎逻辑的方法就是使用const , 但是很遗憾,这样做不会产生预期的效果,虽然const 可以是一个变量常量化,但实际上类中const 修饰的是对象中的成员而非类的。即试剂的作用是为类中的每个对象分配内存,这个对象调用构造函数完成数初始化,一旦完成,就不能再改变。也就是说,对这个const 修饰的成员函数来说,每个不同的对象都可以拥有一个不同的const 值。

const 对象必须在定义时完成初始化。不能先分配内存,过后再赋值,所以在进入构造函数之前,const 数据成员必须已经被赋值。

#include <iostream>
using namespace std ;

class Example{
        int x_ ;
        const int y_ ;
public :
        Example(int x , int y) {
                x_ = x ;
                y_ = y ;                //error
        }
        //othre functions
};
        
        

这样的构造函数是错误的。因为在参数列表(int x , int y)中,系统会先为 x_ 和 y_ 分配单元,等进入函数体之后,才进行赋值。这显然与const的概念不符。const 要求所修饰的对象必须在定义的同时就完成初始化。因此,我们应该使用初始化列表来初始化const 对象,使其在进入函数体之前就已经完成初始化。


#include <iostream>
using namespace std ;

class Example{
        int x_ ;
        int y_ ;
public :
        Example(int x , int y) : y_(y) {        //safe
                x_ = x ;              
        }
        //othre functions
};


这样,cosnt 成员函数 y_ 可以在定义的同时就被初始化。
在C++中,初始化的效率远高于先分配内存再赋值。因此我们可以将一些简单的构造函数的参数尽量放在初始化列表中以提高效率。

#include <iostream>
using namespace std ;

class Example{
        int x_ ;
        int y_ ;
public :
        Example(int x , int y) : x_(x) , y_(y) {}        //also safe    
        //othre functions
};


而初始化列表的顺序最好和数据成员的定义顺序保持一致,否则有可能把自己往坑里推。



2. 编译期间类中的常量

虽说我们解决了const的问题,但之前问题还是没有得到解决——如何在类的每个对象中预设一个固定的值?

答案就是static

static意味着不管这个类的对象被创建多少次,它修饰的对象都只有一个实例,这正是我们需要的类的常量成员。

#include <iostream>
using namespace std ;

class Example{
        int x_ ;
        int y_ ;
        static const int z_ = 100 ;
public :
        Example(int x , int y) : x_(x) , y_(y) {}        
        //othre functions
};


static与其他数据成员区别很大,C++中规定不允许在类内初始化数据成员但static可以,并且,假设我创建了100个Example类的实例,那么每个实例都有一个值为100的const int 。但 z_ 不是他们真正的数据成员,也不和 x_ , y_一样被分配在栈去。而是只被创建一次,并被分配在静态存储区。


3. const对象和成员函数

用户定义的类型和内建类型一样,都可以定义const 对象。

const int i = 1 ;

const Example a(100) ;

都是合法的定义。

我们定义了一个const Example实例a ,a调用构造函数,而之后在该对象的整个生命周期内,都不能修改它的数据成员。

      但在实际中如何保证const对象不会调用一个会修改数据成员的成员函数呢?那就是将所有不会修改数据成员的成员函数都声明为const。 

比如:

void Display() const {

cout << x_ << endl ;

}

我们应该将所有不会改变数据成员的成员函数都声明为const ,一个没有被声明为const的成员函数将会被看成会改变数据成员的函数。而且编译器不允许非它为一个const成员所调用。

简而言之,一个被const 修饰的成员函数有以下两个特征:

①其中的参数不能被改变,包括不能再调用会修改参数的成员函数。

②const对象和非const对象均可以调用const成员函数,但const对象不能调用非const成员函数

     最后还有一个关键字,简单介绍一下:mutable

用来修饰数据成员,意为在const对象中,该关键字修饰的数据成员依然可以被更改


#include <iostream>
using namespace std ;

class Example{
        int x_ ;
        mutable int y_ ;
public :
        Example(int x , int y) : x_(x) , y_(y) {}        
        void Add() {
                x_ ++ ;         //error
                y_ ++ ;         //safe because mutable
        }
        void Display() {
                cout << x_ << y_ << endl ;
        }
};

int main(void) {
        const Example b(3,4) ;
        b.Add() ;
        b.Display() ;
        return 0 ;
}






这样,cosnt 成员函数 y_ 可以在定义的同时就被初始化。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值