1.const在C中是只读变量,在C++中表示常量
以下代码,在C中是错误的,但是在C++中是正确的。
void main()
{
const int n = 10;
int arr [n];
}
2.const不仅可以定义一个常量,也可以定义函数参数
例如:
char *strcpy(char *dest,const char*src)
int strcmp(const char*src1,const char*src2)
3.const可以定义指针
void main()
{
int a = 10;
const int* p1 = &a;
int* const p2 = &a;
int const *p3 = &a;
const int * const p4 = &a;
}
(1)第一个const修饰的是*p1
,也就是修饰的是p1所指向的内容,所以*p1
不可以自加,*(p1)++;
不能执行,p1++;
是可以执行的。
(2)第二个const修饰的是p2本身,它所指向的内容是int,*(p2)++;
可以执行,p2++;
不可以执行的,因为p2本身不可以自加。
(3)第三个const修饰的是*p3
,也就是修饰的是p3所指向的内容,所以*p3
不可以自加,*(p3)++;
不能执行,p3++;
是可以执行的。
(4)第四个const修饰的是*p4,第五个const修饰的是p4本身,*(p4)++;
不能执行,p4++;
也不可以执行。
【说明】把const 和 int 互相颠倒对const修饰什么无影响,const修饰什么是看*
,看*
放在const之前还是放在const之后。
4.const可以修饰函数返回值
(1)以下代码想要在主函数直接通过a.m_i输出i的值以及修改i的值,但是都不能执行,因为m_i是私有的。
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { cout << m_i << endl; }
private:
int m_i;
};
void main()
{
A a(30);
a.print();
//cout << a.m_i << endl; //错
//a.m_i = 50; //错
}
【运行结果】
(2)我们可以给一个接口GetI()函数,用来获取m_i的值,此时就可以通过a.GetI输出m_i的值,但是仍然不能通过a.GetI去修改m_i的值。
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { cout << m_i << endl; }
int GetI()
{
return m_i;
}
private:
int m_i;
};
void main()
{
A a(30);
a.print();
cout << a.GetI() << endl;
//a.GetI() = 50; //错
}
【运行结果】
不能通过a.GetI()修改m_i的值是因为a.GetI()不能作为左值,因为左边的表达式a.GetI()返回m_i,不是把m_i本身返回,是相当于把m_i的值先给了一个临时变量,再把临时变量的值返回去,然后临时变量的空间也消失掉了,所以a.GetI()没有确定的内存空间,不能作为左值,因为要想作为左值必须要有一个确定的内存空间。
(3)如果我们想通过a.GetI()修改a.m_i的值,可以给int GetI()加一个引用,变成int& GetI(),因为引用是当前实体的别名,相当于把m_i本身返回去,此时a.GetI()可以作为左值,就可以通过a.GetI()来修改a.m_i的值
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { cout << m_i << endl; }
int& GetI()
{
return m_i;
}
private:
int m_i;
};
void main()
{
A a(30);
a.print();
a.GetI() = 50;
cout << a.GetI() << endl;
}
【运行结果】
(4)用const修饰函数返回值:const int& GetI()
,此时又不能通过a.GetI()来修改a.m_i的值,但是可以通过a.GetI()来输出a.m_i的值也可以把a.GetI()放在右边。
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { cout << m_i << endl; }
const int& GetI()
{
return m_i;
}
private:
int m_i;
};
void main()
{
A a(30);
a.print();
cout << a.GetI() << endl;
//a.GetI() = 50; //错
}
int GetI()
{
return m_i;
}
const int& GetI()
{
return m_i;
}
(1)第一部分代码的返回值是临时的m_i,临时变量不能作为左值,所以不能修改m_i的值,第二部分代码返回的时候没有生成临时的变量,返回的值就是m_i本身,但是因为加了const所以不能修改m_i的值。
(2)第二部分代码相比较第一部分代码的好处是,第二部分代码虽然因为加了const不能作为左值,但是它返回的就是m_i本身,而第一部分代码不仅不能作为左值被修改,还生成了临时变量,最终临时变量要消失,空间要释放,开辟空间,释放空间,效率就变慢了。
5.const可以修饰常成员函数,const写在函数参数之后
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { cout << m_i << endl; }
void print()const { cout << "const" << m_i << endl; }
//上面两个函数构成重载,函数后面加const可以构成重载
const int& GetI()const //常成员函数,在当前函数中不能修改本类数据成员的值
{
//m_i = 40; //错
return m_i;
}
private:
int m_i;
};
void main()
{
A a(30);
const A b(50); //常对象
a.print();
b.print();
cout << a.GetI() << endl;
}
【运行结果】
【说明】
(1)函数后面加const可以构成函数重载。
(2)函数后面加const叫做常成员函数,常成员函数在当前函数中不能修改本类数据成员的值。
(3)常对象在调用成员函数的时候调用的是常成员函数,如果是非常对象那么调用的就是非常成员函数。如b调用的是void print()const
常成员函数,a调用的是void print()
非常成员函数。
①如果没有非常成员函数,那么a也会调用常成员函数void print()const
。因为虽然a不是常对象,可以修改也可以不修改,它如果调用常成员函数,虽然常成员函数不能修改数据成员的值,但是并不冲突。所以非常对象可以调用常成员函数。
class A
{
public:
A(int i = 0)
{
m_i = i;
}
//void print() { cout << m_i << endl; }
void print()const { cout << "const" << m_i << endl; }
private:
int m_i;
};
void main()
{
A a(30);
const A b(50); //常对象
a.print();
b.print();
}
【运行结果】
②如果没有常成员函数,那么常对象b不会调用非常成员函数void print()
。
class A
{
public:
A(int i = 0)
{
m_i = i;
}
void print() { m_i = 10;cout << m_i << endl; }
//void print()const { cout << "const" << m_i << endl; }
private:
int m_i;
};
void main()
{
A a(30);
const A b(50); //常对象
a.print();
b.print();
}
以上代码不能执行,因为b是const类型的,如果可以调用非常成员函数,那么在非常成员函数中会存在修改m_i的情况,但是b是const类型的就意味着不可以修改m_i的值,这两者冲突。所以常对象不能调用非常成员函数。