1.什么是常成员函数?
在类中可以含有普通成员函数和静态成员函数,而使用 const修饰的普通成员函数称为 常成员函数
const修饰的是普通成员函数中的this指针指向的内存空间
类的普通成员函数中都存在隐藏的 this指针,比如:
class Test
{
private:
int a;
int b;
public:
Test(int a,int b)
{
this->a = a;
this->b = b;
}
void printT()
{
cout << "a = " << this->a << ",b = " << this->b << endl;
}
}
//在C++编译器底层,void printT()函数是这样实现的
void printT(Test *const this) //是一个const型的指针,一旦实参传过来后,指针本身指向就不可以被修改
{
cout << "a = " << this->a << ",b = " << this->b << endl;
//类中的成员变量相当于结构体中的属性,用类定义对象T,相当于用
//结构体类型定义变量T, 然后对象T调用方法时 相当于结构体变量T调用方法,T此时是一个栈空间变量
//调用printT()函数方法时,T会将自己的变量内存空间首地址传给函数printT(),所以对象TT调用方法时相当于把自身的地址也传入了函数中作为一个参数,但C++编译器给我们隐藏了而已
}
这是C++底层绑定成员的方法,而常成员函数是指在此基础上再加一个 const 进行修饰,修饰 this指针指向的内存空间
void printT() const
{
cout << "a = " << this->a << ",b = " << this->b << endl;
}
此时const修饰的是this指针所指向的内存空间,即指向的内存空间的量不可改变,映射到底层表现为
void printT(const Test *const this)
{
cout << "a = " << this->a << ",b = " << this->b << endl;
}
绿色const是普通成员函数和常成员函数均有的,表示的是 指针本身的指向一旦确定不可修改,即 指针常量
而红色const是在普通成员函数括号后面编程 自己添加的,表示的是 指针指向的内存空间的值不可被修改,是一个常量指针,从而this指针是一个指向常量的常量指针
此时该成员函数称为 常成员函数
2.常成员函数的特点:
由于常成员函数中 this指针指向常量,所以常成员函数不能够完成修改 类属性的值的操作,比如:
class Change:
{
private:
int a;
public:
void changeA(int A) // #1
{
this.a = A;
}
void changeA(int A) const // #2
{
this.a = A;
}
}
在上方中,#2 的操作是错误的
同时还要注意:
3.
常成员函数 不能调用 普通成员函数(因为普通成员函数中可能出现更新成员属性值的操作),可以调用其他常成员函数
而普通成员函数是可以调用常成员函数的
4.const关键字来进行函数的重载,还是在上方change类中:
int getval(int val)
{
return val+3;
}
int getval(int val) const
{
return val - 3;
}
而两者互为重载
规则是 常对象(实例化时必须用const进行修饰)调用 常成员函数, 普通对象调用 普通成员函数
5.其他关于const位置的小结
还是对于函数,const来修饰函数的返回值
const来修饰函数的返回值时 分为 指针返回,值返回
5.1当函数是指针返回时,该返回值只能返回给 用 const修饰的同类型的指针
const int* getval()
{
int* tmp = new int(10);
return tmp;
}
由于函数返回指针所指向的值不能被修改,所以
int* a = getval(); //编译错误
const int* b = getval(); //正确
5.2当函数是值返回时,由于返回的值要赋值给另外一个内存空间,所以此时加不加const影响不大
6.const 修饰成员变量
int const a;
const int a;
两者等价,定义常量a
const int* a;
int const* a;
两者等价,均为定义了 常量指针,即指针指向的值不可改变
int * const a;
定义了一个 指针常量,即 指针的指向不可改变
7.const修饰函数参数
const修饰函数参数时,就带来了一个问题。是否可以 根据 函数参数中的 const来进行函数重载,答案是可以的
主要看的就是 函数中的 参数是否 等价于一样,如果等价于一样,则编译器提示错误,函数重定义
如果两者不等价,则根据参数类型发生函数重载
比如:
#include<iostream>
using namespace std;
void fun(const int i)
{
cout << "fun(const int) called ";
}
void fun(int i)
{
cout << "fun(int ) called " ;
}
int main()
{
const int i = 10;
fun(i);
return 0;
}
这样编译则会出错,提示重定义,而不是发生重载
原因在于 函数调用中存在实参和形参的结合,我们的实参 i=10; 不管有没有 const,都不会改变实参的值
再如:
#include<iostream>
using namespace std;
void fun(char *a)
{
cout << "non-const fun() " << a;
}
void fun(const char *a)
{
cout << "const fun() " << a;
}
int main()
{
const char *ptr = "hello world";
fun(ptr);
return 0;
}
其中, char* a 指向的是 字符串变量, const char * a指向的是 字符串常量,两者对于实参是不一样的,前者可以改变实参指向的值,而后者无法改变
但是对于下面的:
#include<iostream>
using namespace std;
void fun(char *a)
{
cout << "non-const fun() " << a;
}
void fun(char * const a)
{
cout << "const fun() " << a;
}
int main()
{
char ptr[] = "hello world";
fun(ptr);
return 0;
}
char* a 与 char* const a 前者是 指针变量,后者是指针常量, 但是由于 函数参数的 实参与形参结合, 两者对于实参来讲是一样的,并不会改变实参的值
所以,综上,函数参数中的 const是可以看做函数重载的标志,但是要视具体情况而言
此外,上面已经知道 带const的常成员函数和普通成员函数也是可以发生重载的