目录
this指针
在讲述this指针时,先看看下面这四个问题,如果这四个问题的答案你都了然于胸的话,就不用再往下看了。
- this指针占不占用类的大小?
- this指针内存放的是谁的地址?
- 静态的成员函数没办法操作this指针?为什么?
- 为什么要设计this指针的存在?
this指针的基本用法:
如果一个类的成员函数的局部变量和这个类的数据成员有相同的名字,或者成员函数的参数表中有和这个类的数据成员相同的名字,那么类的数据成员在成员函数中就会变得不可见,我们如果想要访问类的数据成员就需要用到this指针。
举个例子:
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age; //返回成员变量的值
}
void setage(int age) { //给成员变量赋值
age = age; //正确用法:this->age=age;
cout << "age=" << age << endl;
}
private:
int age;
};
int main() {
student s;
s.setage(18);
cout << s.getage() << endl;
system("pause");
return 0;
}
运行结果如下:
这说明 age=age 这一步没有成功的给成员变量赋值,此时age是系统赋的随机值。
让我们用this指针来试一下:
(这里只给出了运行结果,代码就不再写了,只是把 age=age 改成了 this->age=age )
this指针的另一种用法:
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age;
}
student setage(int age) {
this->age = age;
cout << "age=" << age << endl;
return *this;
}
private:
int age;
};
int main() {
student s;
s=s.setage(18);
cout << s.getage() << endl;
system("pause");
return 0;
}
运行结果如下:
以上就是this指针的两种基本用法。
问题一:
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age;
}
student setage(int age) {
this->age = age;
cout << "age=" << age << endl;
return *this;
}
private:
int age;
};
int main() {
cout << sizeof(student) << endl;
system("pause");
return 0;
}
很显然this指针是不占用类的大小的。
问题二:
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age;
}
student setage(int age) {
this->age = age;
cout << "age=" << age << endl;
return *this;
}
void test() {
cout << "this指针里面存放的地址" << this << endl;
}
//void test(student *this){......}我们提交给编译器后,编译器帮我们加上了一个形参
private:
int age;
};
int main() {
student s;
s.test();
cout << "对象的地址" << &s << endl;
system("pause");
return 0;
}
这说明this指针里面存放的是对象的首地址,this指针是指向对象的。
this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this,不过 this 这个形参是隐式的,它并不出现在代码中(我们把代码交给编译器后,编译器帮我们加上的),而是在编译阶段由编译器默默地将它添加到参数列表中。this指针是类的指针,指向对象的首地址。
我们在调用的时候也是编译器帮我们传递的值 void test(& s)
问题三:
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age;
}
student setage(int age) {
this->age = age;
cout << "age=" << age << endl;
return *this;
}
void test() {
cout << "this指针里面存放的地址" << this << endl;
}
static void lazy() {
cout << "i want to sleep" << endl;
cout << this->age << endl;
}
private:
int age;
};
int main() {
student s;
s.lazy();
system("pause");
return 0;
}
不用等到运行的时候,我在写这个代码的时候就已经报错了。
那为什么this指针只能用于非静态成员函数呢?
#include<iostream>
using namespace std;
class student {
public:
int getage() {
return age;
}
student setage(int age) {
this->age = age;
cout << "age=" << age << endl;
return *this;
}
void test() {
cout << "this指针里面存放的地址" << this << endl;
}
static void lazy() {
cout << "i want to sleep" << endl;
}
private:
int age;
};
int main() {
student::lazy();
student s;
s.lazy();
system("pause");
return 0;
}
我们发现成功的调用了两次静态成员函数lazy(),值得注意的是,我们在第一次调用静态成员函数的时候并没有实例化一个对象。
this指针存储的是实例化对象的首地址,而静态成员函数不用实例化就能被调用,这说明静态成员函数是先于对象存在的,所以说静态成员函数肯定是没有this指针的。
静态成员
在c++类中声明成员时, 加上static关键字声明的成员叫静态成员。
静态数据成员和静态函数成员(因为类的成员本身就分为两类,属性和行为,也就是数据和函数)
静态数据成员需要在类内声明,类外定义。静态成员在类内部声明时加static声明,在类外定义静态成员时无需添加static修饰。
类是一种类型而非真实的数据对象。当需要让类的所有实例共享数据时,就需要用到共享成员,而静态成员就是为了解决这个问题而产生的。
类的对象都可以访问静态成员,但是所有类的成员访问的静态成员都是同一份静态成员。
静态成员变量
1,所有对象共享一份数据
2,在编译阶段分配内存
3,类内声明,类外初始化
4,本质是带类域的全局变量
#include<iostream>
using namespace std;
class age {
public:
static int m_a;//类内声明
};
int age::m_a = 100;//类外初始化
int main() {
//静态成员变量的两种调用方式:1,对象调用2,类调用
age a1;
cout << a1.m_a << endl;
age a2;
a2.m_a = 200;
cout << a1.m_a << endl;
return 0;
}
静态成员函数
- 静态成员函数和静态成员变量一样不属于对象,属于类。
- 静态成员函数不包含编译器提供的 this 指针,在类没有实例化对象前就存在,由于没有 this 指针,所以也就没有特定的成员变量可以使用。
-
静态函数内部不能访问普通成员变量,只能访问静态成员变量。
- 静态成员函数本质上就是带类域的全局函数,可以直接利用类调用静态成员函数,并避免名称冲突的问题。
静态成员函数与成员函数用法上的主要不同为:
静态成员函数可以独立访问,调用静态成员函数时,不需要实例化任何对象。只需要使用 类名 + 命名空间标识符 (::) 加函数名即可调用。
普通成员函数则需要通过对象调用,首先需要实例化一个对象。
静态成员函数和静态成员变量在声明定义以及两种调用方式都相同,就不在赘述了。
常成员
常成员变量
在类中定义的不能修改其值的一些数据成员。
类似于常变量,虽然是变量,也有自己的地址,但是一经赋初值,便不能再被修改。
适用于类中定义一些初始化之后不希望被修改的数据成员。
常数据成员表示它在某个对象生存期内是常量, 即在对象生成时给出常量值,在对象生存期内其值不可改变。而对于整 个类而言,不同的对象其常数据成员的值可以不同。
定义方法:const 类型名 变量名
类中的常数据成员只能通过构造函数的参数初始化表进行初始化,任何其他函数都不能对该成员赋值。
#include<iostream>
using namespace std;
class Mclass
{
public :
int k;
const int M; // 说明常数据成员
Mclass() : M(5) { } // 用初始化列表对常数据成员赋值 , // 这样使得每个对象都有相同的 M 值
void testFun()
{
//M++; // 错误,不能在成员函数中修改常数据成员
k++; // 可以修改一般数据成员
}
} ;
int main()
{
Mclass t1, t2;
t1.k=100;
//t1.M=123; // 错误,不能在类外修改常数据成员
cout<<"t1.k="<<t1.k<<'\t'<<"t1.M="<<t1.M<<endl;
t2.k=200; t2.testFun();
cout<<"&t1.M="<<&t1.M<<endl;
cout<<"t2.k="<<t2.k<<'\t'<<"t2.M="<<t2.M<<endl;
cout<<"&t2.M="<<&t2.M<<endl;
}
常成员函数
在普通的函数后加上关键字 const。
作用是是成员函数无法修改数据成员,一般用于get()函数。
The End :Stick to the light . Embrace it