【C++】类和对象(二)this指针

烧鸡配油茶 2024-07-03 11:35:02 阅读 82

书接上回:【C++】类和对象(一)

文章目录

九、this指针this指针的指出this指针的特性面试题:question:this指针存在内存中的哪个区域:question:this指针可以为空吗

十、C语言和C++实现Stack的对比C语言C++

九、this指针

this指针的指出

我们先来看如下代码:

<code>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 main()

{

Date d1, d2;

d1.Init(2022, 1, 11);

d2.Init(2022, 1, 12);

d1.Print();

d2.Print();

return 0;

}

❓两个对象调用相同的Print()函数,但可以打印出各自对象成员变量的不同值,那编译器是如何知道本次调用是哪一个对象在调用该成员函数呢?

这就引出我们接下来的知识点——隐含的this指针

所有的成员函数被定义出来的时候,默认都会带有一个被隐藏起来的指针,叫做this指针。this指针是成员函数的第一个参数。相应的,对象在调用成员函数的时候,编译器会默认传该对象的地址作为实参,形参位置this指针用来接收对象的地址

请添加图片描述

如果显示写出this指针如图:

请添加图片描述

其实C++跟C语言中的操作类似,只不过C++把调用函数时传参的工作,被调用函数接收参数的工作都交给编译器:

请添加图片描述

this指针的特性

1️⃣this指针是“成员函数”第一个隐含的指针形参,对象调用成员函数的时候不需要程序员传递对象的地址,一般情况由编译器通过ecx寄存器自动传递形参和实参的位置不能显示写,函数内部可以使用。

请添加图片描述

2️⃣this指针的类型本质有const的修饰:类类型* const,eg.(<code>Date* const this)。不能给this指针赋值(改变this指针指向),但是this指向的内容可以被改变

在这里插入图片描述

面试题

❓this指针存在内存中的哪个区域

this指针是一个成员函数的形参,所以在函数栈帧里。

❓this指针可以为空吗

下面的代码运行结果是怎么样的?

<code>// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行

class A

{

public:

void PrintA()

{

cout << _a << endl;

}

private:

int _a;

};

int main()

{

A* p = nullptr;

p->PrintA();

return 0;

}

在这里插入图片描述

答案:B.运行崩溃

p会做为实参传递给this指针,此时this指针为空,编译不会报错。但是<code>cout << _a << endl这句代码对this指针指向对象的成员变量进行访问,则程序会崩溃。所以this指针不能为空

下图验证了this指针是空指针。

在这里插入图片描述

十、C语言和C++实现Stack的对比

C语言

<code>typedef int DataType;

typedef struct Stack

{

DataType* array;

int capacity;

int size;

}Stack;

void StackInit(Stack* ps)

{

assert(ps);

ps->array = (DataType*)malloc(sizeof(DataType) * 3);

if (NULL == ps->array)

{

assert(0);

return;

}

ps->capacity = 3;

ps->size = 0;

}

void StackDestroy(Stack* ps)

{

assert(ps);

if (ps->array)

{

free(ps->array);

ps->array = NULL;

ps->capacity = 0;

ps->size = 0;

}

}

void CheckCapacity(Stack* ps)

{

if (ps->size == ps->capacity)

{

int newcapacity = ps->capacity * 2;

DataType* temp = (DataType*)realloc(ps->array,

newcapacity * sizeof(DataType));

if (temp == NULL)

{

perror("realloc申请空间失败!!!");

return;

}

ps->array = temp;

ps->capacity = newcapacity;

}

}

void StackPush(Stack* ps, DataType data)

{

assert(ps);

CheckCapacity(ps);

ps->array[ps->size] = data;

ps->size++;

}

int StackEmpty(Stack* ps)

{

assert(ps);

return 0 == ps->size;

}

void StackPop(Stack* ps)

{

if (StackEmpty(ps))

return;

ps->size--;

}

DataType StackTop(Stack* ps)

{

assert(!StackEmpty(ps));

return ps->array[ps->size - 1];

}

int StackSize(Stack* ps)

{

assert(ps);

return ps->size;

}

int main()

{

Stack s;

StackInit(&s);

StackPush(&s, 1);

StackPush(&s, 2);

StackPush(&s, 3);

StackPush(&s, 4);

printf("%d\n", StackTop(&s));

printf("%d\n", StackSize(&s));

StackPop(&s);

StackPop(&s);

printf("%d\n", StackTop(&s));

printf("%d\n", StackSize(&s));

StackDestroy(&s);

return 0;

}

可以看到,在用C语言实现时,Stack相关操作函数有以下共性:

每个函数的第一个参数都是Stack*

函数中必须要对第一个参数检测,因为该参数可能会为NULL

函数中都是通过Stack*参数操作栈的

调用时必须传递Stack结构体变量的地址

结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现复杂,涉及大量指针操作。

C++

typedef int DataType;

class Stack

{

public:

void Init()

{

_array = (DataType*)malloc(sizeof(DataType) * 3);

if (NULL == _array)

{

perror("malloc申请空间失败!!!");

return;

}

_capacity = 3;

_size = 0;

}

void Push(DataType data)

{

CheckCapacity();

_array[_size] = data;

_size++;

}

void Pop()

{

if (Empty())

return;

_size--;

}

DataType Top() { return _array[_size - 1]; }

int Empty() { return 0 == _size; }

int Size() { return _size; }

void Destroy()

{

if (_array)

{

free(_array);

_array = NULL;

_capacity = 0;

_size = 0;

}

}

private:

void CheckCapacity()

{

if (_size == _capacity)

{

int newcapacity = _capacity * 2;

DataType* temp = (DataType*)realloc(_array, newcapacity *

sizeof(DataType));

if (temp == NULL)

{

perror("realloc申请空间失败!!!");

return;

}

_array = temp;

_capacity = newcapacity;

}

}

private:

DataType* _array;

int _capacity;

int _size;

};

int main()

{

Stack s;

s.Init();

s.Push(1);

s.Push(2);

s.Push(3);

s.Push(4);

printf("%d\n", s.Top());

printf("%d\n", s.Size());

s.Pop();

s.Pop();

printf("%d\n", s.Top());

printf("%d\n", s.Size());

s.Destroy();

return 0;

}

C++中通过类可以将数据 以及 操作数据的方法放在一起,通过访问权限可以控制哪些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。 而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原,即C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。