详解类与对象(中)【c++】

目录

一、类的作用域

二、类的实例化

三、类对象模型

1、如何计算类对象的大小

2、类的大小

四、this指针

五、类的六个默认成员函数

六、构造函数 

七、析构函数



一、类的作用域

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

class person
{
    public:
        void PrintPersonInfo();
    private:
        char _name[20];
        char _gender[3];
        int _age;
};
void Person::PrintPersongInfo()
{
    cout<<_name<<" "<<_gender<<" "<<_age<<endl;
}

这就是成员函数与类定义分离的写法。日后去工作尽量以这种写法来写。

二、类的实例化

用类创建对象的过程被称为类的实例化

1.类是对付对象进行描述的,是一个模型一样的东西,限定了类有那些成员,定义了一个类但并没有分配实力的内存空间来储存它;可以将类理解为一张图纸,要将房子拆功创建出来(创建对象),房子才能建立起来。一个类可以示例化

2.一个类可以实例化多个对象,实例化出的对象占用实际的物理空间。 

三、类对象模型

1、如何计算类对象的大小

类中既有成员变量又有成员函数,那么一个类的对象中包含了声明?如何计算类的大小?

类对象储存方式可以有如下几个设计

(1)对象中包含类的各个成员

缺陷:每个对象成员中变量都是不同的,但是调用同一份函数,如果按照这种方式储存,当一个类创建多个对象时。每个对象都会储存一份代码,相同的代码保存多次,浪费空间。

(2)代码只保存一份,在对象中存放代码的地址

(3)只保存成员变量,成员函数放在公共的代码段 

但最后编写c++的大佬选择了哪一种——答案是第三种。第一种太浪费空间了,但第二第三种事什么情况呢

第二种方法就好比你在一个小区里,小区里有一个健身场所,为了让每个用户都能找到健身场所,居委为每个人都修了一条专属的道路。

第三种方法就很纯粹,反正都是在一个小区里,也不怕找不到健身场所,没修任何门每个业主(对象)都能很方便的享受到

2、类的大小

class A
{
public:
	void func();
private:
	int _a;
};
class B
{
public:
	void func2();
};
class C
{
public:

};

计算以上三个类的大小得出的结果如下: 

 得出结论:类的大小就等于类的成员变量大小之和,但要注意内存对齐

那为什么空类也有内存空间呢,这其实是占位,表示内存空间存在。

内存对齐规则:

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

四、this指针

在定义一个类的时候,我们经常会用到变量,这个变量在类里面默认是private的,外界无法访问的,就比如:

class A
{
    int _a;
};

等效于

class A
{
  private:
    int _a;  
};

这两者效果是一样的:

 不可访问,外界无法访问,但是类内部的函数在没有传参的情况下是怎么实现调用类成员函数的呢?

其实你认为的没有传参,编译器偷偷帮你传了一个参——this指针。这个this指针就是你定义的这个类的类指针。

 printf里的指针可加可不加编译器已经帮你搞定了。

看看下面两道面试题选什么:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A {
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0; }
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 int _a;
};
int main()
{
    A* p = nullptr;
    p->PrintA();
    return 0; }

答案是CB。

第一题:

printf函数是存放在公共区域的,p->print就相当于是将公共区域的函数地址调用过来了。

第二题:

第二题在print函数里用到一个指针:p->_a这时候p是空指针,根本就没有_a的内存空间,导致程序直接报错了。

五、类的六个默认成员函数

任何类在生成的时候都会有6个默认成员函数。

默认成员函数:用户没有希纳是实现,编译器会自动生成的成员函数为默认成员函数。

以下来依次讲解着几个函数

六、构造函数 

钩爪函数是特殊的成员函数,需要注意的是,构造函数虽然被称为构造,但它的主要任务不是开辟空间而是初始化对象。

特征:

1.函数名与类名相同

2.无返回值

3.对象实例化时编译器自动调用对应的构造函数

4.构造函数可以重载

5.如果你没有在类里定义一个构造函数,编译器会自己生成一个构造函数

 class Date
 {
  public:
      // 1.无参构造函数
      Date()
     {}
  
      // 2.带参构造函数
      Date(int year, int month, int day)
     {
          _year = year;
          _month = month;
          _day = day;
     }
  private:
      int _year;
      int _month;
      int _day;
 };
  
  void TestDate()
 {
      Date d1; // 调用无参构造函数
      Date d2(2015, 1, 1); // 调用带参的构造函数
  
      // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
      // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
      // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
      Date d3();
 }

6.关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用?
解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如: int/char..,。自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。

7.无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写,编译器默认生成的构造函数,都可以认为是默认构造函数。
 

七、析构函数

构造函数可以看作是对一个对象的初始化,那么我们现在讲解的析构函数则是在一个对象度过生命周期时销毁对象的函数。这就类似于destory函数。

析构函数是特殊的成员函数,其特征如下:

1.析构函数名是在类名前加上字符~。

2.无参数无返回值类型。
3.一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
4.对象生命周期结束时,C++编译系统系统自动调用析构函数。
5.关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器
生成的默认析构函数,对自定类型成员调用它的析构函数。
6.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
 

~符号另一个含义是按位取反,在这里有异曲同工之妙。它的意义是与构造函数区分,因为名字一样嘛。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一周学八天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值