this,常成员函数,常对象
介绍
this关键字
在C++中,this是一个指针,指向当前对象的实例。它在类的成员函数中使用,允许你访问对象的成员变量和成员函数。以下是关于this指针的一些关键点:
(1) 指向当前对象:this指针是一个隐式参数,指向调用成员函数的对象。例如,在一个成员函数中,this->memberVariable可以用来访问当前对象的成员变量。
(2) 类型:this的类型是指向类的指针。例如,在类MyClass的成员函数中,this的类型是MyClass*。
(3) 用于区分成员变量和参数:当成员变量的名称与参数名称相同时,可以使用this来区分。例如:
class MyClass {
public:
int value;
MyClass(int value) {
this->value = value; // 使用this指针区分成员变量和参数
}
};
(4) 返回当前对象:this指针可以用于返回当前对象的引用,常用于链式调用。例如:
class MyClass {
public:
MyClass& setValue(int value) {
this->value = value;
return *this; // 返回当前对象的引用
}
};
(5) 在静态成员函数中不可用:this指针只能在非静态成员函数中使用,因为静态成员函数不属于任何特定对象。
(6) 常量成员函数中的this:在常量成员函数中,this的类型是指向常量对象的指针(const ClassName*),这意味着你不能在常量成员函数中修改对象的成员变量。
以下是一个简单的示例,展示了this的用法:
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
MyClass(int value) {
this->value = value; // 使用this指针
}
MyClass& setValue(int value) {
this->value = value; // 使用this指针
return *this; // 返回当前对象的引用
}
void display() const {
cout << "Value: " << this->value << endl; // 使用this指针
}
};
int main() {
MyClass obj(10);
obj.display(); // 输出: Value: 10
obj.setValue(20).display(); // 链式调用,输出: Value: 20
return 0;
}
常成员函数和常对象
在C++中,常成员函数和常对象是用于控制对象状态和行为的重要概念。它们通过使用const关键字来确保对象的不可变性,从而提高代码的安全性和可读性。下面是对这两个概念的详细讲解:
常对象(const Objects)
常对象是指在创建对象时,使用const关键字修饰的对象。这意味着该对象的状态(即其成员变量)不能被修改。
特点:
不可修改:常对象的非静态成员变量不能被修改,尝试修改会导致编译错误。
只能调用常成员函数
常量引用:常对象通常通过常引用传递,以确保在函数调用中不会修改对象。
class MyClass {
public:
int value;
MyClass(int v) : value(v) {}
};
void display(const MyClass& obj) {
// obj.value = 10; // 错误:不能修改常对象的成员
std::cout << "Value: " << obj.value << std::endl;
}
int main() {
const MyClass obj(10); // 创建常对象
display(obj); // 正确,传递常对象
return 0;
}
在这个示例中,obj是一个常对象,display函数接受一个常对象的引用作为参数,确保在函数内部不会修改obj的状态。
常成员函数(const Member Functions)
常成员函数是指在成员函数的声明中使用const关键字修饰的函数。这表示该函数不会修改调用该函数的对象的状态。
不能修改成员变量:在常成员函数中,不能修改任何非静态成员变量。
可以被常对象和非常对象调用
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
// 常成员函数
void display() const {
std::cout << "Value: " << value << std::endl; // 可以读取,但不能修改
}
// 非常成员函数
void setValue(int v) {
value = v; // 这是一个非常成员函数,可以修改
}
};
int main() {
MyClass obj(10);
obj.display(); // 输出: Value: 10
const MyClass constObj(20);
constObj.display(); // 输出: Value: 20
// constObj.setValue(30); // 错误:不能调用非常成员函数
return 0;
}
在这个示例中,display是一个常成员函数,它可以在常对象上调用,而setValue是一个非常成员函数,不能在常对象上调用。
常成员函数与常对象的关系
常对象只能调用常成员函数:如果你有一个常对象,你只能调用该对象的常成员函数。这是为了确保对象的状态不会被意外修改。
常成员函数可以被常对象和非常对象调用:常成员函数可以被常对象和非常对象调用,但在常对象上调用时,函数内部不能修改对象的状态。
使用场景
常对象:常对象通常用于需要保护对象状态不被修改的场景,例如在函数参数中传递对象时,确保不会意外修改对象。
常成员函数:常成员函数用于提供只读访问对象状态的接口,确保对象的状态在调用过程中保持不变。
用法
常成员函数和常对象很多人并不在意,确实都写普通变量也可以;但是在大型程序中,尽量加上const 关键字可以减少很多不必要的错误。
(1) 常成员函数和常对象
常成员函数就是无法修改成员变量的函数。可以理解为将this指针指向对象用const修饰的函数;
常对象就是用 const 修饰的对象,定义好之后就再也不需要更改成员变量的值了。 常对象在大型程序中还是很有意义的;
#include <iostream>
class Test
{
public:
Test(std::string name_, int age_);
~Test();
void output(); // 普通成员函数
void display() const; // 常成员函数,无法修改成员变量;
// 常成员函数 本质是普通成员函数的this加上const修饰,但是参数中没有this,所以直接函数后加个const
std::string name;
int age;
};
Test::Test(std::string name_, int age_) : name(name_), age(age_) {}
Test::~Test(){}
// 普通成员函数实现
void Test::output()
{
std::cout << "调用普通成员函数" << std::endl;
std::cout << "name = " << name << ", age = " << age << std::endl;
}
// 普通成员函数的本质 全局函数 + this指针(Test类指针常量)
void output(Test* const myThis)
{
std::cout << "调用普通成员函数" << std::endl;
std::cout << "name = " << myThis->name << ", age = " << myThis->age << std::endl;
}
// 常成员函数实现
void Test::display() const
{
std::cout << "调用常成员函数" << std::endl;
//myThis->age = 100; // 此时不能修改指针指向的对象
}
// 常成员函数的本质 全局函数 + this指针(Test类指针常量指向常量)
void display(const Test* const myThis)
{
std::cout << "调用常成员函数" << std::endl;
//myThis->age = 100; // 此时不能修改指针指向的对象
}
int main()
{
Test t1("zhangsan", 20);
t1.output();
output(&t1); // 传入对象地址
t1.display();
display(&t1); // 传入对象地址
const Test t2("lisi", 25); // 不希望t2对象被修改,所以使用常对象
//t2.age = 80; // t2是常对象,不能修改对象t2
return 0;
}
(2) 常成员函数注意事项:
因为类的成员函数已经将 this 指针省略了,只能在函数后面加 const 关键字来实现 无法修改类成员变量的功能了(上述代码里也进行了演示)
- 常函数无法调用了普通函数,否则常函数的这个“常”字还有什么意义
解释:如果一个常函数里可以调用普通函数,那么我们可以调用set函数,去修改对象,那么此时这个常成员函数就没有意义了,所以语法规定,常函数无法调用普通函数
- 成员函数能写作常成员函数就尽量写作常成员函数,可以减少出错几率
- 同名的常成员函数和普通成员函数是可以重载的,常量对象会优先调用常成员函数,普通对象会优先调用普通成员函数
#include <iostream>
class Test
{
public:
Test(std::string name_, int age_);
~Test();
// 两个output函数是重载关系
void output(); // 普通成员函数
void output() const; // 常成员函数
std::string name;
int age;
};
Test::Test(std::string name_, int age_) : name(name_), age(age_) {}
Test::~Test(){}
void Test::output()
{
std::cout << "调用普通成员函数output" << std::endl;
std::cout << "name = " << name << ", age = " << age << std::endl;
}
void Test::output() const
{
std::cout << "调用常成员函数output" << std::endl;
std::cout << "name = " << name << ", age = " << age << std::endl;
}
int main()
{
Test t1("zhangsan", 20); // 普通对象
t1.output(); // 普通对象会优先调用普通成员函数
const Test t2("lisi", 30); // 常对象
t2.output(); // 常对象会优先调用常成员
return 0;
}
常对象注意事项:
- 常对象不能调用普通函数,原因和常成员函数不能调用普通函数是一样的
- 常成员函数和常对象要多用,这真的 是一个非常好的习惯,写大项目可以少出很多bug