# C++类和对象剖析

本文详细介绍了C++中的类,包括类的定义、访问限定符(public、protected、private)、作用域概念以及类的大小计算。讨论了类中函数的存储方式,并通过实例解释了成员函数的调用机制和内存对齐规则。此外,还阐述了this指针在成员函数中的应用,展示了如何通过this指针访问和修改对象的成员变量。
摘要由CSDN通过智能技术生成

1.C语言中的类:

1.1 类的定义:

​  类其实是C语言中结构体的升级,与C语言相比,c++中的类不仅支持成员变量,还支持成员函数。

struct CppTest 
{
    int a;
    void init()    //在类中可以定义函数
    {
        a = 0;
        next = nullptr;
    }
    int* next;
};


1.2 访问限定符

​    public,protected和private。

​    public限定符表明类中的所有成员都可以在类外被直接访问。

​    在此阶段protected和private的作用是一样的,都表明类中成员不能在类外被直接调用。

​    不管是什么限定符,在类内都是可以调用的。

1.3 类的作用域

​    在c++中只要有“{ }”就有域。

​    什么是影响生命周期的东西?

​    存在什么区域才是真正影响生命周期的东西。

 

​    类定义了一个新的作用域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用::作用域操作符指明成员属于哪个作用域。

 #辨别声明与定义
 开了空间就是定义,没开空间就是声明。类和结构体一样,在定义一个结构体类型变量时并不会为成员开辟空间,只有用这个结构体类型(类)定义一个对象时才会为成员开辟空间,这个过程叫类的实例化。但是就算没有实例化对象,计算sizeof(类)并不会得到零,因为类的定义好比图纸,实例化对象就相当于根据这个图纸制造出房子,就算没有真实的房子也能根据图纸计算出房子应该有的大小。

int age;   //定义

class person
{
public:
    void printpersoninfo();//声明
private:
    char name[20];  // 声明
    char _gender[3];// 声明
    int age;// 声明        
};

​   所以在上述代码中,全局变量age开了空间是定义,而类中的成员全部是声明。

1.4 如何计算类的大小

​    因为类中可以包含成员函数,所以类大小的计算并不像结构体那么简单。

1.4.1 类中的对象存储可能有多种方式:

 存储方式一:

 

​    这种方式弊端很明显,当定义多个对象时,虽然每个成员变量都是独立空间,但是每个对象调用的函数都是同一个,将这些函数存进去会大大浪费空间。

 

存储方式二:

 

​    这种方式把函数的地址存到一个函数表中,但是这里并没有采用这种方案,而是用了方式三。

存储方式三:

 

​    这种存储方式将函数放在公共代码区,当调用函数时并不会去对象的区域找,而是在编译时根据函数名直接call

class person
{
public:
    void func()
    {
        cout << "func" << endl;
    }
}; //这是类的定义


//看这段代码,猜猜运行结果是什么
person* ptr = nullptr;
ptr->func();

​    运行结果是正常运行,可以打印func。

 

这也验证了,调用类中的函数时编译器并不会去解引用ptr,否则解引用空指针会报错。

思考: 既然类中函数在公共代码区,为什么调用时还要加上对象名呢?

 1.4.2  内存对齐规则

> 1. 第一个成员在与结构体偏移量为0的地址处。
> 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
>    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
>    VS中默认的对齐数为8
> 3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
> 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是
>    所有最大对齐数(含嵌套结构体的对齐数)的整数倍。  

​    既然函数并不占据空间,那么类的大小计算规则就和结构体一样了。以下面代码为例

class sample
{
public:
    char i;  // 1byte
    int a;   // 4byte
};

​    在vs下的默认对齐数是8byte,而类中最大的对齐数是4byte,所以对齐数设置成4byte。所以i放在偏移量为1的位置,a放在偏移量为4的位置,最终结果是8byte。

> ​    #求特殊类型的大小
>
> ​    当定义一个空类型或者仅含有构造函数或者析构函数时,在vs下这些类型的大小均为1。因为类型必须在内存中占用一定空间,否则无法使用。所以VS给这些类型分配1byte空间。

> #命名方法总结
>
> // 单词和单词之间首字母大写间隔 --驼峰法
>
> // 函数名,类名等所有单词首字母大写
>
> // 变量首字母小写,后面所有单词首字母大写
>
> // 成员变量,首单词前加 ' _'
>
> ————————————————————
>
> // 单词全部小写,单词之间用_分隔

##  2.this指针 

```c++
class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year; // 年
    int _month; // 月
    int _day; // 日
    int a;
};
int main()
{
    Date d1, d2;
    d1.Init(2022, 1, 11);
    d2.Init(2022, 1, 12);
    d1.Print();
    d2.Print();
    return 0;
}
```

观察上面代码,在Init函数中__year是否和成员变量_ _year是一块空间呢?但是这里还只是声明呀,哪里会开空间呢?怎么能够修改呢?

这里就涉及到了this指针,在C++语法中编译器会悄咪咪地给类的成员函数和main函数内调用成员函数传参部分加上this指针。
 

void Init(Date* const this, int year, int month, int day)//会加上this指针做形参
{
   _year = year;

   _month = month;
   _day = day;
}

 int main()
 {
     d1.Init(&d1, 2022, 1, 11);//会加上&对象名,对象名由前面的名字决定,所以就算成员函数在公共区,我们也要用对象名去调用。
     d2.Init(&d2, 2022, 1, 12);
     return 0;
 }

ps:this指针存在栈区。因为this指针属于形参。vs可能会优化,把this指针放到寄存器中。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值