• 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

  • 相关阅读:
    解决phpcms图片太大撑破表格图片自适应图片按比例缩小
    CSS代码使纯英文数字自动换行
    CSS网页布局错位:CSS宽度计算
    CSS控制div宽度最大宽度/高度和最小宽度/高度
    鼠标HOVER时区块动画旋转变色的CSS3样式掩码
    记录--正则表达式
    写在前面
    ruby Mixin用法
    ruby 模块 的引入
    ruby 编写迭代器
  • 原文地址:https://www.cnblogs.com/icmzn/p/5059428.html
Copyright © 2020-2023  润新知