文章目录
一. 静态成员
① 静态成员变量
静态成员变量就是普通的成员变量前面加上static
关键字就是静态成员变量.
- 所有的对象共享同一份静态成员变量.
- 在编译阶段分配内存,存储在全局数据区
- 在类内声明,类外初始化,需要在类外单独分配空间.
- 生命周期不依赖任何的对象,为程序的整个生命周期.
- 即可以通过对象来访问,也可以通过类名来访问
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/
#include <iostream>
using namespace std;
class Simple
{
public:
Simple()
{
mSimpleCountPrivate++;
cout << "Simple的构造函数被调用,已被构造的次数" << ++mSimpleCount << endl;
}
~Simple() {};
int get_obj_count(void)
{
return mSimpleCountPrivate;
}
public:
static int mSimpleCount;
private:
static int mSimpleCountPrivate; // 私有的静态成员变量,外部不能直接访问
};
int Simple::mSimpleCount = 0; // 类的静态成员变量需要在类外分配内存空间
int Simple::mSimpleCountPrivate = 0;
int main()
{
Simple s1; // 第一次构造
cout << "已经创建的对象的个数: " << Simple::mSimpleCount << endl;
Simple s2; // 第二次构造
cout << "已经创建的对象个数: " << s2.get_obj_count() << endl;
Simple s3; // 第三次构造
cout << "已经创建的额对象个数: " << s3.mSimpleCount << endl;
system("pause");
return 0;
}
结果:
② 静态成员函数
- 普通的函数前面加上
static
关键字就是静态成员函数- 静态成员函数没有
this
指针,所以只能访问静态成员变量- 所有的对象共享静态成员函数,无论对象是否已经创建,都可以访问静态成员函数
- 静态成员函数,不能调用普通的成员函数,只能调用静态的成员函数
- 普通的成员函数有
this
指针,可以访问内部的任意成员,而静态成员函数没有this
指针,只能访问静态成员(静态成员变量和静态成员函数)
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/
#include <iostream>
using namespace std;
class Student
{
public:
Student(const char *name, int age, float score)
{
mName = name;
mAge = age;
mScore = score;
mTotal++;
mScores += mScore;
}
void show()
{
cout << mName << "的年龄是: " << mAge << ", 成绩是: " << mScore << endl;
}
static int get_total()
{
return mTotal;
}
static float get_scores()
{
return mScores;
}
private:
const char *mName;
int mAge = 0;
float mScore;
static int mTotal; // 总人数
static float mScores; // 总分数
};
// 定义静态成员变量
int Student::mTotal = 0;
float Student::mScores = 0.0;
int main()
{
(new Student("张三", 15, 100))->show();
(new Student("李四", 13, 89))->show();
(new Student("王五", 12, 100))->show();
(new Student("小明", 11, 82))->show();
int total = Student::get_total();
float scores = Student::get_scores();
cout << "当前共有" << total << "名学生,总成绩是" << scores << ", 平均分是: " << scores / total << endl;
system("pause");
return 0;
}
结果:
二. 成员变量和成员函数分开存储
① 空对象占用字节的大小
在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上.
而一个空类它也是占用字节的,占用1个字节.
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/
#include <iostream>
using namespace std;
class Empty
{
// 空类什么都没有
};
int main()
{
// 实例化两个对象
Empty e1;
Empty e2;
cout << "e1 对象占用内存大小: " << sizeof(e1) << endl;
cout << "e2 对象占用内存大小: " << sizeof(e2) << endl;
cout << "e1 的地址: " << &e1 << endl;
cout << "e2 的地址: " << &e2 << endl;
system("pause");
return 0;
}
结果:
分析
- 空类之所以会占用一个字节,其实这里是用来占位的
- 因为空类也可以实例化,如果不占用1个字节,就没办法分配内存.
- 当空类作为基类的时候,该类的大小就会被优化为0,这就是所谓的空白基类的最优化.
② 成员函数和变量分开存储
- 定义对象的时候会分配存储空间,但是只会为对象的成员变量分配存空间,成员函数则存放到公共的代码区.
- 每个对象占用的的存储空间只是该对象的数据部分,而不包括成员函数.
- 而成员函数存放在代码区,只有一份,那么怎么区分是哪个函数来调用的呢,通过this指针.
三. this指针
① 为什么需要this指针
- 在建立对象的时候,对象中的数据成员会分配自己独立的存储空间.但是对于成员函数来说,一个函数的代码段在内存中只有一份.也就是说,同一个类中的不同对象在调用自己的成员函数时,其实它们调用的是同一个函数代码.
- 既然是调用同一个代码段,那么如何确保调用的是自己的数据成员呢? 通过this指针.其实每一个成员函数中都有一个隐藏的参数,是一个指针,名字叫this.它的值是当前被调用的成员函数所在的对象的起始地址.其实就是当前对象存放数据的起始地址.所以其对数据的引用,其实是通过this-> 这种方式去操作this指向的对象.
② this指针的用途
- 用途1: 当形参和成员变量同名时,可以用this指针来区分
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/
#include <iostream>
using namespace std;
class Person
{
public:
Person(string name,int age)
{
this->name = name;
this->age = age;
}
private:
string name;
int age = 0;
};
int main()
{
Person p("Fioman", 18);
system("pause");
return 0;
}
- 在类的非静态函数中返回对象本身,可使用return *this,用于链式编程.
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/
#include <iostream>
using namespace std;
class Person
{
public:
Person(int money)
{
this->money = money;
}
Person &add_money(Person &p)
{
this->money += p.money;
return *this;
}
public:
int money = 0;
};
int main()
{
Person p1(5);
Person p2(100);
Person p3(20);
p1.add_money(p2); // 5 + 100 = 105
p1.add_money(p2).add_money(p3); // 105 + 100 + 20 = 225
cout << p1.money << endl;
system("pause");
return 0;
}
③ this指针使用的时候注意事项
- this指针只能在成员函数中使用
- 全局函数,静态函数都不能使用this指针
- 实际上成员函数的第一个参数为 T * const this.
class A
{
public:
// 这个函数的原型应该是int func(A* const this,int p){}
int func(int p)
{
cout << "in func this 指针的地址: " << this << endl;
}
};
- this在成员函数开始前构造,在成员函数结束后清除
- 这个生命周期同任何一个函数的参数是一样的,没有任何区别.
- 当调用一个类的成员函数时,编译器将类的指针作为函数的this参数传递进去. 如: A a; a.func(10);
其实编译器会翻译成A::func(&a,10);- 编译器通常会对this指针做一些优化,因此,this指针的传递效率比较高.
- this指针是什么时候创建的
在成员函数开始执行之前构造,在成员函数执行结束后清除
- this指针存放在何处?堆,栈,全局变量,还是其他?
this指针会因编译器的不同而有不同的放置位置.可能是栈,也可能是期存器,甚至是全局变量.
- this指针是如何传递类中的函数的
大多数的编译器通过ecx寄存器传递this指针.在call之前,编译器会把对应的对象地址放到eax中.this是通过函数参数的首参来传递的.this指针在调用之前生成.类在实例化的时候,只分配类中的数据成员的空间,并没有为函数分配空间.自从类定义完成以后,它就在那里,就一份.
- this指针是如何访问结构体中的变量的
如果不是类,而是结构体的话,那么,如果通过结构体指针来访问结构体的变量呢?
在C++中,类和结构体只有一个区别: 类的成员默认是private的,而结构是public.
this是类的指针,如果换成结构体,那么this就是结构的指针了.
- 我们只有获得一个对象后,才能通过对象this指针,如果知道了一个this指针的位置,可以直接使用吗?
this指针只有在成员函数中有定义.所以,你获取一个对象后,也不能通过对象使用this指针.所以,我们无法知道一个对象的this指针的位置(只有在成员函数中才有this指针的位置).知道了this指针的位置之后,可以直接使用它.
- 每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?
普通的类函数(不论是成员函数,还是静态函数)都不会创建一个函数表来保存函数指针.只有虚函数才会被放到函数表中.但是,即使是虚函数,如果编译器能明确知道用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是会直接调用该函数.