C++总的const使用说明

C++总的const使用说明

1. const修饰类成员变量

  程序:

#include <iostream>
using namespace std;

class A
{
    public:
        A(int size) : SIZE(size) {};
    private:
        const int SIZE;
};

int main()
{
    A a(100);
}

  说明:
  (1)    在类中声明变量为const类型,但是不可以初始化;

  (2)    const常量类的成员变量的初始化必须在构造函数初始化列表中初始化,而不可以在构造函数函数体内初始化。

  (3)  如果其作为C类的成员定义,因为不可以在C类定义创建对象,则可以采用如下措施:

         使用指针,然后在C类的构造函数中,用new 在堆空间创建对象,然后天数const的成员初始化。

  

   此时的const变量属于具体的一个对象,如何在整个类中都恒定不变呢

   答案是利用枚举

#include <iostream>
using namespace std;

class A
{
    private:
        enum {SIZE = 100};
    public:
        int array[SIZE];
};

int main()
{
    A a;
}

  问题说明:

  (1)枚举常量不会占据对象的存储空间,在编译时被全部求值

  (2)但是,它隐含的数据对象类型为整形,不能表示其他类型

2. 必须在构造函数的初始化列表中初始化的情况

  (1)类的const常量;

  (2)类的引用类型成员;

#include <iostream>
using namespace std;

class A
{
    public:
        A(int &v) : i(v), p(v), j(v) {}
        void print_val() { cout << "hello:" << i << "  " << j << endl;}
    private:
        const int i;
        int p;
        int &j;
};

int main(int argc ,char **argv)
{
    int pp = 45;
    A b(pp);
    b.print_val();
}

   究其因

  ① const对象引用只能列表初始化但是不能赋值

  ②  构造函数的函数体内只能做赋值而不是初始化,因此初始化const对象或引用的唯一机会是构造函数函数体之前初始化列表中

  ③ 明白两个概念:

  从无到有叫初始化,初始化(调用拷贝构造函数创建了新对象

  赋值(调用赋值操作符没有创建新对象,而是对已有的对象赋值。

  (3)没有默认构造函数的类类型成员

#include <iostream>
using namespace std;

class Base
{
    public:
        Base(int a) : val(a) {}
    private:
        int val;
};

class A
{
    public:
        A(int v) : p(v), b(v) {}
        void print_val() { cout << "hello:" << p << endl;}
    private:
        int p;
        Base b;
};

int main(int argc ,char **argv)
{
    int pp = 45;
    A b(pp);
    b.print_val();
}

   原因同样是创建对象时,要初始类成员的每一个成员

  (4)如果类存在继承关系,派生类必须在其初始化列表中调用基类的构造函数

#include <iostream>
using namespace std;

class Base
{
    public:
        Base(int a) : val(a) {}
    private:
        int val;
};

class A : public Base
{
    public:
        A(int v) : p(v), Base(v) {}
        void print_val() { cout << "hello:" << p << endl;}
    private:
        int p;
};

int main(int argc ,char **argv)
{
    int pp = 45;
    A b(pp);
    b.print_val();
}

3. const成员函数与非const 成员 函数问题

  (1) 任何不修改数据成员的函数都应该声明为const类型

  如果在编写const成员函数时,①不慎修改了数据成员,②或调用了其他非const成员函数,编译器就会指出错误。应该养成一个好的习惯。

  注意:在const修饰类的成员数据时,一般在const声明在函数声明的后边;

#include <iostream>
using namespace std;
class Stack
{
    public:
        void Push(int item);
        int Pop(void);
        int GetCount(void) const;//const 后置
    private:
        int m_num; 
        int m_data[100];
};

int Stack::GetCount(void) const
{
    ++m_num;     //编译错误,企图修改数据成员
    Pop();       //编译错误,企图调用非const函数
    return m_num;
}

  (2)同一个类中,可以仅通过是否是const定义两个函数名字、参数、返回值完全相同的两个成员函数,依据类对象是否为const对象分别调用。

  程序:

#include <iostream>
using namespace std;

class A
{
    public:
        A(int v): val(v) {}
        void print_val() { cout << "not const:" << val << endl;}
        void print_val() const { cout << "const print_val:" << val << endl;}
    private:
        int val;
};
int main(int argc ,char **argv)
{
    A b(45);
    b.print_val();

    const A a(12);
    a.print_val();
}

  输出:

  

  总结:

  同函数名、参数、返回值可以仅通过是否为const来定义为类的两个成员函数。

  在调用时,const对象调用const成员函数,非const对象调用非const成员函数。

(3)非const的成员函数,可以调用const的成员函数,

  当一个只有const成员函数的时候,非const对象也可以调用const成员函数

class A  
{  
public:  
       A( void )  
       {  
       }  
         
       void func( void ) const  
       {  
           cout << "const version" << endl;  
       }  
};  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    //非const对象调用const成员函数   
  
    A obj;  
    obj.func( );  
      
    //const对象调用const成员函数   
    const A obj_const;  
    obj_const.func( );  
      
    system( "PAUSE" );  
    return EXIT_SUCCESS;  
    return 0;  
}  

(4)const对象是不可以调用类中的非const成员函数

 我们知道c++在类的成员函数中还会隐式传入一个指向当前对象的this指针,所以在test类中,实际的print函数应该是这样的void print(test * this);,这代表一个指向test对象的指针this被传入到了print函数中

假如现在我们用test类创建一个对象,

 test obj1(12);
 obj1.print();

  第二句,obj1.print();其实相当于print(&obj1);,即把当前的对象obj1的指针传递到print()函数,这是没问题的

  如果用test类创建一个const对象,然后去调用print()函数呢?这就会出现问题

const test obj2(122);
obj2.print();

  这时obj2对象的指针就会传递给test *this 指针,而obj2的地址翻译成指针类型应该是这样的,const test* this,即这时会出现类型不匹配的错误,在visual studio 中会出现类似于下面的错误:

  所以通过上面的说明,我们知道了为什么const 对象不能调用非const成员函数。

4. const的一些问题

  (1)不可以在const函数中改变成员变量的值,那么有没有办法改变?

  答案是可以的,把成员变量声明为mutable类型。看程序

#include <iostream>
using namespace std;

class A
{
    public:
        A(int v): val(v) {}
        void print_val() { cout << "not const:" << val << endl;}
        void print_val() const { val++; cout << "const print_val:" << val << endl;}
    private:
        mutable int val;
};
int main(int argc ,char **argv)
{
    A b(45);
    b.print_val();

    const A a(12);
    a.print_val();
}

  输出:

  

  说明:

  mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。

  在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

  我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰

  (2)当类中只有const函数,非const对象是否可以调用const函数?

  答案是可以的,范围并没有被扩大。

  但是:只有const函数时,非const对象不可以调研那个const函数(否则,类的数据变量就会发生变化)。

  (3)当类中存在只有 是否为const 不同的两个函数时,const函数是否可以暂时调用那个非const函数?

   答案是可以的。用const_cast将转化掉表达式的const性质

#include <iostream>
using namespace std;

class A
{
    public:
        A(int v): val(v) {}
        void print_val() { cout << "not const:" << val << endl;}
        void const print_val() const { cout << "const print_val:" << val << endl;}
    private:
        int val;
};
int main(int argc ,char **argv)
{
    A b(45);
    b.print_val();  //非const

    const A *a = new A(45);
    const_cast<A*>(a)->print_val();  //()调用非const的重载函数
    a->print_val();  //调用const的从在函数
}

  输出:

  

  注意;const_cast<A*> (a)只对本地转化有效,且必须使用类的指针进行处理。

  单纯用类转化不行,直接用类的对象不行。

const A a(45);
const_cast<A> a.print_val();

  编译不通过,错误

  (4)返回类型是const是怎么回事?

  const返回类型只有在修饰指针或引用是才有用。单凭const返回类型不可以重载。

 

  参考网址:

        http://www.cnblogs.com/kaituorensheng/p/3244910.html

原文地址:https://www.cnblogs.com/icmzn/p/5059428.html