从化网站制作,全屋定制十大名牌是哪些,网站的公司,wordpress标题相关this指针 前言一、this指针的引出问题 二、this指针的特性三、例题什么时候会出现编译报错什么时候会出现运行崩溃this指针存在哪里this指针可以为空吗 四、C语言和C实现Stack的对比C语言实现C实现 前言
this指针是一个特殊的指针#xff0c;在C类的成员函数中使用。它指向调… this指针 前言一、this指针的引出问题 二、this指针的特性三、例题什么时候会出现编译报错什么时候会出现运行崩溃this指针存在哪里this指针可以为空吗 四、C语言和C实现Stack的对比C语言实现C实现 前言
this指针是一个特殊的指针在C类的成员函数中使用。它指向调用该成员函数的对象的地址。通过使用this指针成员函数可以访问和修改调用它的对象的属性和其他成员函数。这种机制使得成员函数能够识别和操作其所属的对象从而实现了面向对象编程中的封装性和数据隐藏。 一、this指针的引出
this指针是C中的一个特殊指针它指向当前对象。它的引入主要是为了解决成员函数与成员变量同名的问题。
在一个类中成员函数可以访问类的成员变量。当类的成员变量与成员函数的参数同名时如果没有使用this指针编译器无法区分两者。因此this指针的引入使得编译器能够准确地识别成员变量与成员函数的参数。
this指针可以在非静态成员函数中使用它指向调用该函数的对象可以通过this指针访问对象的成员变量和成员函数。
this指针的使用场景主要有以下几种
在类的成员函数中如果成员变量与成员函数的参数同名可以使用this指针来明确指出要访问的是成员变量。在类的成员函数中如果需要返回当前对象本身可以使用return *this;。在类的成员函数中如果需要在函数中访问当前对象的地址可以使用this指针来获取。
总结来说this指针的引入解决了成员函数与成员变量同名的问题同时也提供了一种简便的方式来访问当前对象的成员变量和成员函数。
问题
我们先来定义一个日期类 Date
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;
}对于上述类有这样的一个问题
Date类中有 Init 与 Print 两个成员函数函数体中没有关于不同对象的区分那当d1调用 Init 函数时该函数是如何知道应该设置d1对象而不是设置d2对象呢
C中通过引入this指针解决该问题即C编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数让该指针指向当前对象(函数运行时调用该函数的对象)在函数体中所有“成员变量”的操作都是通过该指针去访问。只不过所有的操作对用户是透明的即用户不需要来传递编译器自动完成。
二、this指针的特性
this指针的类型类类型* const即成员函数中不能给this指针赋值。只能在“成员函数”的内部使用this指针本质上是“成员函数”的形参当对象调用成员函数时将对象地址作为实参传递给this形参。所以对象中不存储this指针。this指针是“成员函数”第一个隐含的指针形参一般情况由编译器通过ecx寄存器自动传递不需要用户传递禁止在静态成员函数中使用静态成员函数不属于任何对象因此不能使用this指针。允许链式调用this指针的存在允许成员函数进行链式调用即返回*this指针。可以修改成员变量使用this指针可以访问和修改当前对象的成员变量。可以调用其他成员函数使用this指针可以调用当前对象的其他成员函数。可以用于比较和判断是否为同一对象使用this指针可以比较两个对象是否为同一个对象。 三、例题
// 1.下面程序编译运行结果是 A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void Print(){cout Print() endl;}
private:int _a;
};
int main()
{A* p nullptr;p-Print();return 0;
}在这个代码中首先定义了一个类 A其中有一个公有的成员函数 Print() 和一个私有的成员变量 _a。
然后在主函数 main 中定义了一个 A 类型的指针 p并将其初始化为 nullptr。接下来通过 p 指针调用 Print() 函数。 由于 p 是一个空指针正常来说试图通过空指针调用函数会导致运行时错误但是本题并没有对指针进行解引用调用而是直接使用cout函数所以会正常运行。 // 1.下面程序编译运行结果是 A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:void PrintA(){cout _a endl;}
private:int _a;
};
int main()
{A* p nullptr;p-PrintA();return 0;
}在这个代码中首先定义了一个类 A其中有一个公有的成员函数 Print() 和一个私有的成员变量 _a。
然后在主函数 main 中定义了一个 A 类型的指针 p并将其初始化为 nullptr。接下来通过 p 指针调用 Print() 函数。 由于 p 是一个空指针试图通过空指针调用函数会导致运行时错误本题是对p指针解引用调用_a,所以会出现运行崩溃即this-_a)
什么时候会出现编译报错
编译报错通常在编程过程中出现以下是一些常见的情况 语法错误如果代码中包含了错误的语法编译器将无法解析代码并报错。例如缺少括号、缺少分号、错误的变量命名等。 类型错误如果代码中使用了错误的类型或进行了不兼容的类型转换编译器将报错。例如将字符串赋值给整数类型的变量、使用未声明的变量等。 缺少依赖库如果代码中使用了某个依赖库但没有将其正确导入或链接到项目中编译器将无法找到该库并报错。 重复定义如果代码中定义了重复的变量、函数或类型等编译器将报错。 系统限制有时编译器会实施一些限制例如最大堆栈大小、代码行数限制等。如果代码超过了这些限制编译器将报错。
当编译报错时通常会提供详细的错误信息其中包含了错误的位置和具体原因开发人员可以根据这些信息来定位和修复错误。
什么时候会出现运行崩溃
运行崩溃是指在程序运行过程中突然停止或无响应的情况。崩溃可能出现在各种软件和硬件系统中以下列举了一些常见的运行崩溃的情况 程序错误程序中存在错误或漏洞导致程序运行时崩溃。这可能是由于编程错误、内存泄漏、资源耗尽等引起的。 内存问题程序运行时需要占用大量内存但系统资源不足导致程序崩溃。这可能是由于内存泄漏、内存溢出、过多的进程占用内存等引起的。 硬件故障硬件设备出现故障导致程序无法正常运行或崩溃。这可能是由于硬盘故障、电源故障、内存损坏等引起的。 操作系统错误操作系统出现错误导致程序无法正常运行或崩溃。这可能是由于操作系统错误、驱动程序冲突、系统文件损坏等引起的。 网络问题程序依赖网络连接进行通信但网络出现故障或断开导致程序无法正常运行或崩溃。
总而言之运行崩溃可能由多种原因引起包括程序错误、内存问题、硬件故障、操作系统错误、网络问题等。对于开发者来说重要的是通过调试和测试找出并修复这些问题以确保程序能够稳定运行。
this指针存在哪里
this指针是在C类中的一个特殊指针它指向当前对象的地址。在类的成员函数中可以使用this指针来访问当前对象的成员变量和成员函数。在C中每个非静态成员函数都隐含地包含一个this指针。
即this是个形参存放在栈区中或叫ecx寄存器上述图片可以直接展现编译器将d1的地址存放到寄存器中
this指针可以为空吗
this指针可以为空。在C中this指针指向当前对象的地址如果对象不存在即为空this指针也将为空。在访问对象的成员函数时需要先判断this指针是否为空以避免访问空指针错误。
这个问题的具体示例在上述的题目我们给this传入了一个空指针我们不对this指针进行解引用程序是正常运行的我们一旦解引用程序便会报错。
四、C语言和C实现Stack的对比
C语言实现
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语言中需用用户自己维护。