[C++] 类与对象(上)2

简介: [C++] 类与对象(上)2

7、类对象模型

如何计算类对象的大小呢?

例如:

class A
{
public:
  void AInit(int a, int b)
  {
    cout << "void AInit(int a, int b)" << endl;
  }
private:
  int _a;
  int _b;
};
class B
{
private:
  int _a;
  int _b;
};
class C
{};
int main()
{
  cout << "类A的大小:" << sizeof(A) << endl;
  cout << "类B的大小:" << sizeof(B) << endl;
  cout << "类C的大小:" << sizeof(C) << endl;
  return 0;
}

运行结果:

总结:

1、成员函数不算在类的大小中;

2、类的大小只与成员变量有关,并遵循结构体对齐规则;

3、空类的大小为1字节(不存储数据,只是占位,表示对象存在过)。

7.1 内存对齐规则

1. 第一个成员在与结构体偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

VS中默认的对齐数为8

3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

7.1 类对象的存储方式

为什么类中的成员函数不占空间?那成员函数是存在哪里呢?

实例化后的类中只存储类成员变量

成员函数保存在公共的代码段。

我们画图来理解一下:


8、this指针

我们这里写一个日期类来看一下:

class Date
{
public:
    void Init(int year, int month, int day)
    {
    _year = year;
    _month = month;
    _day = day;
    }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  d1.Init(2023, 7, 30);
  return 0;
}

这里看似 Init 函数只有三个形参

调用的时候传了三个参数

实际上,这里还隐含了一个 this 指针。

我们这里画图来看一下:

这里对成员变量赋值的时候,前后都会加一个 this-> 来接引用访问。


8.1 this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。

2. 只能在“成员函数”的内部使用。

3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。

4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。


因此,我们写的时候就不可以这样写:

class Date
{
public:
  void Init(Date* this, int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  d1.Init(&d1, 2023, 7, 30);
  return 0;
}


this指针隐含着,如果我们自己加上就是错误的。

this在实参和形参的位置上不能显示写

但是在类里面可以显示的用

如下:

class Date
{
public:
    //this在实参和形参的位置上不能显示写
    //但是在类里面可以显示的用
  void Init(int year, int month, int day)
  {
    this->_year = year;
    this->_month = month;
    this->_day = day;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  d1.Init(2023, 7, 30);
  return 0;
}

8.2 this指针是否可以为空

我们来看下面几段代码:

class Person
{
public:
  void PersonInit()
  {
    cout << "void PersonInit()" << endl;
  }
private:
  int _age;   //声明
  char _name[20];
};
int main()
{
  Person* p = nullptr; //初始化为空指针
  p->PersonInit();
    return 0;
}

运行结果:

这里我们就会产生疑问,p是空指针为什么可以解引用呢?还是正常运行。

这里对于函数定义在类里面且短小,编译器会当作内联函数,直接展开,并不会解引用;

而如果声明与定义分离或者编译器不将其当作内联函数,就是call Init函数(调用函数)的地址,也不是解引用。

我们继续看:

class Person
{
public:
  void PersonInit()
  {
    cout << "void PersonInit()" << endl;
  }
//private:
  int _age;   //声明
  char _name[20];
};
int main()
{
  Person* p = nullptr; //初始化为空指针
  p->PersonInit();
  p->_age = 1;
  return 0;
}

这就会导致运行崩溃,对空指针的内容进行解引用。

我们接着上面看:

class Person
{
public:
  void PersonInit()
  {
    cout << _age << endl;
  }
//private:
  int _age;   //声明
  char _name[20];
};
int main()
{
  Person* p = nullptr; //初始化为空指针
  p->PersonInit();
  return 0;
}

这里在调用Init函数的时候,函数里面产生了解引用,但是this是空指针,这里就会运行崩溃。

空指针不会编译错误,只会导致运行崩溃。

相关文章
|
28天前
|
编译器 C++
C++之类与对象(完结撒花篇)(上)
C++之类与对象(完结撒花篇)(上)
33 0
|
22天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
21 4
|
22天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
19 4
|
22天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1
|
23天前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
15 0
|
28天前
|
编译器 C++ 数据库管理
C++之类与对象(完结撒花篇)(下)
C++之类与对象(完结撒花篇)(下)
28 0
|
28天前
|
编译器 C++
C++之类与对象(3)(下)
C++之类与对象(3)(下)
31 0
|
28天前
|
编译器 C++
C++之类与对象(3)(上)
C++之类与对象(3)
16 0
|
28天前
|
编译器 C++
C++之类与对象(2)
C++之类与对象(2)
29 0
|
28天前
|
存储 编译器 C++
C++之类与对象(1)(下)
C++之类与对象(1)(下)
25 0