C++总的const使用说明

时间:2023-03-10 02:13:14
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();
}

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

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

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

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

  

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

   答案是利用枚举

#include <iostream>
using namespace std; class A
{
private:
enum {SIZE = };
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 = ;
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 = ;
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 = ;
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[];
}; 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();
b.print_val(); const A a(12);
a.print_val();
}

  输出:

  aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAASYAAAAtCAIAAACMFlH6AAADxElEQVR4nO2c26GsIAxFqYuCqMdqbMZivB/Hi4QkEIXB116fjobEYQtGiFsBAANxVzsAwLeA5AAYCiQHwFD6Sm4Ozk9LV5MX0C+KZfLOOT+Jhwlh7tEeeACQHKdbFJN33ntZctDYV4HkOJ2imINzYZ4DJAdS3LruE50wJ3Me1lHWv14kz4XIL00TJtrGxHqn6oM5inRaF+Y57FYORLEZkezHE/y0rJAcoOyj3ORdCHv/mHze07Ijc+AdrnV8mINjbZADVR8ORsEasEYRxamcGZWmSi7s8tZ1C94HkRzpfPRRLD6YWd9sk5zURnrM4kM5ijUOPiVMUWyaU9Syt6pJLvESg96noKNc+r/TjiD3irw/NUmu2vMsPpSjiOcU54ytY/UyJSkTSXLdWwQPwig5pU90lVztYpMPFsllV7PfGwVATZokpzxNwBv54ihXM9s+PT6cRoLkvoNVciPe5aQRJ8X4LleSnDTmnJNcNWNZaDEHL3Nfwiq5lSUeyBtLck6eDzySjsszluxI1Ye65KhLZ6OoZSzTE7Nrs5CWydetgPdAvsvFGRA7sEHmTLKWyKetEz0pn5exp7/qgyWKvwEsNXE2inLGMrehKvbkXQLPBcuaARgKJAfAUCA5AIYCyQEwFEgOgKFAcgAMBZIDYCiQHABDgeRksCYE/Ii7Se4u21jaJHd9FMkCm/ZNw+oC0KVXM18CkvsF94nirCdRTCFoi83pWlG+PBbIQHK/4D5RtHuiWFj49vr7RH1rqOQeUupHJFlnnJqil0fnYmESdlJprlQPs1MU6UXSTafNFDp6RQaGLUgHhIQ9SBZ2yT2n1I/OHJz3+aZsbnDfTxB3HPCuonpSDfMXNWBKJVsWyQWTJ5YtSOZYsOvPxn/JParUT+lqsf9zXVce7SVPqmG2T7HyG1XrzfrvFU/qW5CssWBWaWWT3EtK/Yj7yrkbte3nZU8MYXYtWGTw97TkDFhLDGKAM7JJ7iWlfuSqB3K9CJOtiyRH741kjb8zXiY56O0Yo0e5mtlRo9zdJbeHwktF8G+Gl41ypddIIPP/Xe5RpX5U7O9yt5dcNMtfgHl7pyXXlLEUU1Oghp6xvG+pHx2esRQ+Hw2QXGvZpWjEh8CNZ4/H/cPFkSh2x85lLKVnNFKWFsh3uaeU+lHZtEQL/Szkd4Es+yixWTHXZepTUEhfbUXv4rJQ2VWi4F7KL8ClW6U1AclVudvqkzZMwxcAVwLJATAUSA6AobxHcuZlhwBcyXsk9wC0nAPyD18CkgNgKJAcAEOB5AAYyj86qS44Lae6oAAAAABJRU5ErkJggg==" alt="" />

  总结:

  同函数名、参数、返回值可以仅通过是否为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 ;
}

(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 中会出现类似于下面的错误:

C++总的const使用说明

  所以通过上面的说明,我们知道了为什么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();
b.print_val(); const A a();
a.print_val();
}

  输出:

  aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAM0AAAAvCAIAAADPUtm3AAADpklEQVR4nO2dS5qlIAyFWRd76SmjXkGvwtW4GRdjD8rilQSicBG955+VV0MSjxEEvjI7AJ/H3O0A+AqgMzAC8+fvv7t9AO8HOgMj6K6z1Rm7bF1N3kC/KLbFGmPswh5OcGuP9iYFOmPpFsVijbWW19mrhZUBnbF0imJ1xrh1ddDZr85+67hbo5JOsrP/pI4v9ckvTe+DtI2F3BLRB3UU8VvLrasLVk5EcRjh7PsT7LLt0FlWzxZrnAtJWWye3uzI6miWWyvB6gxpIzlQ9eFkFKQBbRRekcKZXl6izlzQtCzWd5DrLMl4+tCxjyC5IW0649qIj2l8KEex+zJTQhXFITRBIqFVSWeRl68vb6SexcGm0fOpyJPYpLNqujU+lKPw5xRfia1VeVuivj+ns+4tTo5eZ0IiuuqsdrHKB43OsqvJ7413PTWp0pnwCL2FL61nNbPtb//T4yHojP3roHP/jKstMcr+WUlnXHW5prPqeLPQYs7bO2gndLaTHnTSC4nOyUdzZwZT+XiTHKn6UNdZ6tLVKGrjzfjE7NospG2xdSvPJv9+5gs8OXCQvBJ4ASWfoC6kL3/tkOdc9EETxU+pik1cjaI83sxtiDK9mKVngXl0MALoDIwAOgMjgM7ACKAzMALoDIwAOgMjgM7ACKAzkS/4Sj+OCXU2ywqZNp3dH0U05dG+8lScfE1mVuQZWujsQ8wTxVVPvIKcE1Y3ZNO+dGo6AJ19iHmiaPdEbUFedUJ09pA9ICzRxHZsKr3cO+cX75OTSm+cepidoogv4pKeNlPQQUUlitVNvXX2nD0gMqsz1ubLWanBsGrDr+ugCRI9qYb5iX0SpW0NG+eCyhPN6iZtLAUnIp09ag9I6Wr2plMxVx7ikifVMNvfVnmiagsh5d8rntRXN2mW09dKdtDZS/aAsCtyqRu1hbtlTxRhdt3JovD3ss4UKC2wL46DoLOX7AHhF0nzy8tVtm7SWZobzhrtB96ss9KZN9SzmtlR9Wx2nYVQ6Mpy+m1vgnp2nMp6EfXPHrUHRETfP5teZ94s7dTS9i7rrOd4U9ZQcbw57x4QGTre3Lixx8d11rofxxuxzlHj2f0M31rORBEcuzbeZD9PKL/TPmUPiMghoHQHyJb8zpCNHTkOK+oNO312msiTPmkWty3VWiUK6iXfqS2n6kSME84HtKEqVGA00BkYAXQGRvAqnamn/MBoXqWzByD1z+We9juAzsAIoDMwAvzfHTAC6AyM4D/5VfHqxqoEAQAAAABJRU5ErkJggg==" alt="" />

  说明:

  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();
b.print_val();  //非const const A *a = new A();
const_cast<A*>(a)->print_val();  //()调用非const的重载函数
a->print_val();  //调用const的从在函数
}

  输出:

  aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAANMAAABGCAIAAADZzjZ+AAAD8klEQVR4nO2b27mEIAyEqYuCqIdqaMZiPA/HD4EEiIJG1/kfXQ0JO8vFZcwKgAZGOwHwUaA8oAOUB3SA8oAOUB7QYaLygjPWL/Pi6TCvisVbY4z17OUMF2a09zKgvIJpVXhrrLW88j4ptQIor2BSFcEZ40JwUF4NE0d/F5KJgPTX+t+Z/ASRfTI0i+RtePIlVXMQV5HOdS4Et0c5UMUWhIsfb7B+WaG8OtuY561xbu8mb8sOL64ER/t9dLQIzpA2sgvdHA5WQRqQVhE1WrkzCq6qPLervC7f32ZXXvYd5D9M9mdKvqIx5XFtpNckObSrWONQ1EJUxSa9imj2VmvKS7L87BCYjHlp+Xl/8J1TduuQ8rpfgCSHdhXxnuZEOjpyLz7ZVXDKm97iS5Eor9I1U5XXe1iUg0R5xdPk80Ed5CFFyqv8qH6dz415vbDja4bDOy0oL7l8/zqPG39ShOu8lvK4Eeic8rp720aLJV9d6ImUt5K1ebaaSe4pd45HNm7l3pZc6ebQV16e0tkqenvb9Mbi2aKkxdt+lN/EZBOEC+tKL2xkEwkvqeyV2IkOLScrMhZUc5BU8T+cpSHOVtHe25YxqsI92Uu/AU4MAB2gPKADlAd0gPKADlAe0AHKAzpAeUAHKA/oAOUBHXAavgAOoJuA8grgALoJKK8ADqCbgAMIDiAd4ACCA0gHOIDaIas3NUQDB5CEz52GhwPoIcABBAeQDp8b83ph4QC6CTiA4ADSAQ4gOIB0gAPoTBVwAI2DEwNABygP6ADlAR2gPKADlAd0gPKADlAe0AHKAzpAeQwf/mfhPh6lvKecFxpTnn4Vyd80w5lc5mOC8qbznComZHKdjwnKm85zqhjO5EofU6K8l7hvWJK/8NNQ+eMxuWiSIDe15ql+mZOqSB/iOj1vpqGtjvJ0fUwm5vgS902d4Iy15ZFgGnA/sRLPtNAurGbSLfMKP0rLPrJwKYgyUfYxmRjmLe6b1tOsDKi8+z3VUl67zPE5ruyo3vBS/7yTia6PyUgee4f7hj3VTNPoHX5uZyIoc6qHSJDvaeVJc7jGx2QED73EfcN3EH9oXxRLSXl533DR6HpysvLu8DHdOub1wt415j1deXsp9Lw+fdc4f8y7xcdktgzf476pIl/nPV55MSxdHNP2TitP18dU2ds+131Th+5tF25Xc7nyRp1QMYh1jgYvRon9Tc+RKvbEOu9l9jD00UEf0/4+7y3umypbB+XemyX7vD2H8JNMjCK2Ss3x+LDvndZ1zb8I65clV1+nCpqlko/pUf9hjCFbCIOHAOUBHaA8oMMPKQ+8CigP6ADlAR2gPKADlAd0gPKADlAe0OEPdUnxBhhoZboAAAAASUVORK5CYII=" alt="" />

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

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

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

  编译不通过,错误

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

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

 

  参考网址:

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