【C++】2、面向过程和面向对象常见问题

本文探讨了C++中对象内存分配、成员方法的存储、this指针的作用,以及构造函数和析构函数的工作原理。重点讲解了new操作符在对象创建过程中的职责,包括内存申请、对象构造及地址返回。同时,分析了构造函数的调用顺序和对象生命周期中的内存管理。此外,还讨论了C++中'一切皆对象'的思想及其在实际编程中的体现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象和面向过程常见问题

c++中对象内存分配:

class CGoods
{
private:
    char _name[21];
    int _amount;
    float _price;
    float _total_price;
public:
    void RegisterGoods(const char[],float price,float total_price);
    void CountTotal();
    void GetName();
    int GetAmount();
    float GetPrice();
    float GetTotalvalue() const;
};

在这里插入图片描述

每个对象有自己的数据区,但是函数的成员方法共享存储区域。

问题1:C++为了节省空间,将各个对象的成员方法存放到公用代码区,那么C++是如何区别每个函数属于不同的对象呢?

答案:引入this指针。

首先来看一段代码:

#include<iostream>
using namespace std;

class CGoods
{
private:
    char _name[21];
    int _amount;
    float _price;
    float _total_price;
public:
    void RegisterGoods(const char[],float price,float total_price);
    void CountTotal();
    void GetName();
    int GetAmount();
    float GetPrice();
    float GetTotalvalue() const;
};

float CGoods::GetTotalvalue()const
{
    
}

int main()
{
    CGoods c1;
    c1.RegisterGoods("C++",19,88.88);
    //等价于:RegisterGoods(&c1,"C++",19,88.88);
    CGoods c2;
    c2.RegisterGoods("JAVA",23,99.9);
    //等价于:RegisterGoods(&c2,"JAVA",23,99.9);
    CGoods c3;
    c3.RegisterGoods("Python",21,79.8);
    //等价于:RegisterGoods(&c3,"Python",21,79.8);
    return 0;    
}


C++中,当使用对象 + . 调用成员函数时,实际上编译器会隐式的传递对象的地址作为第一个参数,这个地址也是this指针的地址。依靠这个,与其他对象调用的成员函数区别。

问题2:this指针是在什么时期添加的?

回答:this指针是在编译时期添加的。

问题3:p1 p2 p3 在栈上分配空间,那么他们在分配的时候,在这个空间上有没有对象?

class Pointer
{
public:
    Pointer()
    {
        row = 0;
        col = 0;
    }
    Pointer(int r, int c)
    {
        row = r;
        col = c;
    }
    // Pointer(int r = 0, int c = 0)
    // {
    //     row = r;
    //     col = c;
    // }
    //Pointer p4;   //存在二义性,不知道是调用无参构造还是带有默认参数的构造函数
private:
    int row;
    int col;
};

int main()
{
    Pointer p1;                 //构造无参的构造函数
    Pointer p2(10,20);          //构造含有参数的构造函数
    Pointer p3();               //不可这样使用,函数声明 int fun()

    //问题:在程序执行时,分配空间,代码区,数据区,堆区,栈区.给主函数分配栈帧,系统给对象分配空间.
    //p1 p2 p3 在栈上分配空间,在这个空间上有没有对象?
    //|  p1 |
    //|  p2 |
    //|  p3 |
    //没有,必须调动对象所属的构造函数来创建对象.并且给对象的成员进行初始化.
    //编译器在编译链接过程结束后,调用时会为p1,p2分配8个字节.仅仅是分配空间,满足使用
    //并不存放对象,在对象调用构造时,才会将对象存放在内存中.
    return 0;
}

问题4:什么是析构函数

当定义一个对象的时候,C++会自动调用构造函数建立对象并且进行初始化,那么当一个对象的声明周期结束时,C++也会自动调用一个函数注销该函数,那么这个特殊的成员函数即为析构函数。

特点:

  • 析构函数名和类名一样,~ + 类名
  • 析构函数没有返回类型,且没有参数
  • 一个类只有一个析构函数,但可以有多个构造函数
  • 对象注销时,系统自动调用析构函数
  • 如果没有显示的析构函数,系统会构造一个隐式的析构函数

问题5:构造函数和析构函数返回值

构造函数与析构函数是没有返回值的,但是我认为构造函数有隐含的返回值(this指针)。构造函数是在类的对象产生时自动调用的,构造函数被调用也就意味着产生了一个对象,而this指针是与对象实体相关联的。

class Pointer
{
public:
    Pointer(int var)
    {
        _var = var;
        cout << "_var:" << endl;
    }
private:
    int _var;
};

int main()
{
    Pointer p1(10);
    return 0;
}

当对象被实例化的时候,构造函数会返回一个首地址,系统先会申请一块地址空间用来存放对象,随后这个对象的地址会赋值给this指针。详细情况在问题10有说明。

问题6:new对象的两个方法

1、运算符调用

2、构建new

Pointer g_pt (12,23);   //全局对象
//进入主函数之前,调用构造函数创建全局对象

int main()
{
    Pointer p1(100,200);

    Pointer *p = NULL;
    p = new Pointer(10,20);
//new 的两个用法,运算符调用
    //new 做的三件事情
    //1 申请空间:malloc从堆区申请空间
    //2 构建对象:在空间构造对象
    //3 返回地址:将构造对象的地址返回
    
//构建new,对s指向的空间中,调用构造函数来构建对象
    Pointer *s = (Pointer *)malloc(sizeof(Pointer));
    //上述代码空间中是否有对象?      无
    new(s) Pointer(12,23);

//深入理解:对象和空间的关系
//有对象必须有空间
//有空间不一定有对象

    s->~Pointer();  //s调动析构函数,释放对象的资源,并没有释放空间
    free(s);        //释放空间
    s = NULL;

    delete(p);      
    //delete 做的三件事情
    //1 调用析构
    //2 释放空间
}

问题7:new 和 delete

new 做的三件事情:
1、 申请空间:malloc从堆区申请空间
2 、构建对象:在空间构造对象
3 、返回地址:将构造对象的地址返回

delete 做的两件事情:
1 、调用析构
2 、释放空间

问题8:构造函数构造顺序

//一个问题
class Object
{
private:
    int val;
public:
    Object(int x)
    {
        val = x;
        cout << "create :" << val << endl;
    }    
};
Object o1(1);

int main()
{
    Object o2(2);
}

Object o3(3);

输出结果:

1 3 2

对于输出结果的详细分析请见 3、C++构造和析构

问题9:C++中一切皆对象思想

class Object
{
private:
    int sum;
    int num;
public:
    Object(int x = 0, int y = 0): sum(x),num(y){}
};
//C++中重要思想,一切皆对象
int main()
{
    int a = 10;
    int b(10);
    int c = int (10);       //伪构造函数
	//上述过程与下面类似
    Object obj;
    Object obj(10);
    Object obj2 = obj;
    
    int *c = new int(20);
}

问题10:this指针传递问题

this调用,this指针在c++中存放在ecx或者cx寄存器进行传递。

A*const register this;

通过C++编译生成反汇编如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-liONJr6w-1641654149697)(2、c++中对象内存分配.assets/image-20220107152754471.png)]

1、成员函数的THIS指针如何进行传递:

​ 如果是使用对象 .调动成员方法时,逻辑上是面向对象,但是物理上还是面向过程。会将对象的地址传递给成员函数的this指针。

2、对象的地址传递:

​ 对于c++来说,使用thiscall调用约定,直接进行传递,lea ecx , [c1]传递。我们将对象的地址获取,到达成员函数内部时,我们通过mov指令将ecx寄存器的值传递给this指针。

3、什么时候使用入栈的形式调用参数:

​ 我们可以改写成C的调用约定,我们在函数前面添加__cdecl。通过lea指令将c1的地址传递给ecx寄存器。使用push eax直接传给this指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值