妇联加强网站平台建设高端网站改版顾问
妇联加强网站平台建设,高端网站改版顾问,WordPress模板申报功能下载功能,wordpress后台去掉左上角1个wordpress更新目录
一、面向过程和面向对象初步认识
二、类的引入和定义
2.1类的引入
2.2类的定义
三、类的访问限定符及封装
3.1访问限定符
3.2封装
四、类的作用域
五、类的实例化
六、类的对象大小的计算
6.1如何计算对象的大小
6.2类对象的存储方式
七、类成员函数的thi…目录
一、面向过程和面向对象初步认识
二、类的引入和定义
2.1类的引入
2.2类的定义
三、类的访问限定符及封装
3.1访问限定符
3.2封装
四、类的作用域
五、类的实例化
六、类的对象大小的计算
6.1如何计算对象的大小
6.2类对象的存储方式
七、类成员函数的this指针
7.1this指针的引出
7.2this指针的特性 一、面向过程和面向对象初步认识 面向过程关注的是过程分析出求解问题的步骤通过函数调用逐步解决问题。
例如洗衣服
拿盆子——放水——放衣服——放洗衣粉——手搓——换水——手搓——拧干——晾衣服
我们知道C语言面向的是过程例如我们要得到两数之和的结果,那么得造一个和函数先进行传实参形参相加得到参数之和返回之和的值这就是得到两数之和的一个过程。
面向对象关注的是对象将一件事情拆分成不同的对象靠对象之间的交互完成。 还是洗衣服有四个对象人、衣服、洗衣粉、洗衣机
那么洗衣服过程人将衣服放入洗衣机、倒入洗衣粉启动洗衣机洗衣机就会完成洗衣过程人不需要关注洗衣机是如何洗衣服的。
那么照样我们也要得到两数之和的结果就不需要去实现函数了而是直接用函数就行这个函数是已经被实现的这就是直接使用对象不需要关注实现过程。 那么还有疑问的是对象之间的操作怎么看起来也是一个过程其实是不同角度产生的看法那么对于同一件事情洗衣服从过程来看这个衣服需要执行被洗的过程在乎的是怎么洗的过程而从对象来看只需要用洗衣机完成洗衣服怎么洗的过程不在乎。其实这就相当与面向对象是以更高的角度去看待面向过程。 我再从更高的角度去看待面向对象那么面向对象又可以看成面向过程。所以对于任何实现从不同角度既可以看成面向过程也可以看成面向对象 对于c我们将其看成面向对象的语言因为对标C语言c很多实现要比C语言简单的多不用造轮子(自己实现没必要去浪费时间做的函数当然你以更高的角度来看c实现的函数也可以看成过程 但是你得在更高的角度弄出点东西来不然也改变不了啥。
二、类的引入和定义
2.1类的引入 回顾C语言实现栈时需要有一个结构体存放定义的变量而具体的实现需要额外定义函数完成压栈、出栈、销毁栈等。那么在c中结构体不仅可以定义变量也可以定义函数了同样我们用栈来举个例子 #include iostream
using namespace std;typedef int DataType;
struct stack
{//栈的初始化void Init(size_t capacity){_array (DataType*)malloc(sizeof(DataType*) * capacity);if (nullptr _array){perror(malloc fail);exit(-1);}_capacity capacity;_size 0;}//压栈void Push(const DataType data){_array[_size] data;_size;}//取队头元素DataType Top(){return _array[_size - 1];}//栈的销毁void Destroy(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}//变量的定义DataType* _array;size_t _capacity;size_t _size;
};int main()
{stack s;s.Init(5);s.Push(1);s.Push(2);s.Push(3);cout s.Top() endl;s.Destroy();return 0;
}
运行结果 从上面代码可以看出我们将变量的定义与函数的实现都放在结构体中且这些变量可以在函数中使用像这种将函数和变量都放在一个结构体中在这种情况下在c中我们称之为类也就是说C语言中的结构体在c中升级成了类当然类依然支持C语言中的结构体用法毕竟c兼容C语言嘛。那么接下来讲解类定义的详细用法 注意上述结构体的定义在c中更喜欢用class来代替其实struct和class还是有区别的在类的访问限定中会讲解。 2.2类的定义
形式规则
class className
{//类体由成员函数和成员变量组成};//一定要注意后面的分号class为定义类的关键字className为类的名字{}中为类的主体注意类定义结束时后面分号不能省略。 类体中内容称为类的成员类中的变量称为称为类的属性或成员变量类中的函数称为类的方法或者成员函数 以上是类定义的形式规则但对于类中的成员函数定义和成员变量命名也有一定的规则。
成员函数的定义有两种方式
1.成员函数的声明和定义都放在类体中需要注意的是编译器可能会将其当成内联函数处理。 2.类声明放在.h文件中成员函数放在.cpp中注意成员函数名前需要加类名::
//声明放在类的头文件fun.h中
#include iostream
using namespace std;class Person
{
public://显示基本信息void showinfo();
public:char* _name;char* _sex;int _age;
};//定义放在类的实现文件中
#include fun.hvoid Person::showinfo()
{cout _name - _sex - _age endl;
}int main()
{Person s;s._name (char*)张三;//由于张三是字面常量类型为const char*而_name为char*类型s._sex (char*)男;s._age 18;s.showinfo();return 0;
} 运行结果 一般情况下最好采用第二种方式但在之后的讲解中为了方便可能会使用方式一。但在以后的工作中的话那尽量使用方式二 。
成员变量命名规则的建议
#include iostream
using namespace std;class Date
{
public:void Init(int year){//这里的year到底是成员变量还是函数形参,虽然知道左边的year是定义的变量而右边的year是形参的year//但难免带来一种令人不友好的感觉year year;//所以一般建议定义的变量加上前缀或者后缀,对于我而言习惯加上前缀int _year year;int year_ year;int myear year;}
private:int year;int _year;int year_;int myear;
};int main()
{Date d;d.Init(3);return 0;
}
注意默认直接在类里面定义的函数就是inline函数不需要加inline关键字当然在编译时展不展开函数还是取决编译器 。
三、类的访问限定符及封装
3.1访问限定符 在上述代码中看到我们加了public、private这类符号是什么 像这类符号我们称之为访问限定符其实这是c实现封装方式的必要手段用类将对象的属性和方法结合在一块让对象更加完善再通过访问访问限定符选择性的将其接口提供给外部的用户使用。 那具体是啥意思访问限定符有哪些look 访问限定符用来限定类外是否能访问类里面的成员访问限定符分为三类public公有protected保护和private私有
访问限定符说明
1.public表示类外是可以访问类里面被public修饰的成员
2.protected和private表示类外不能直接访问类里面被这两个修饰的成员他们是类似的但还是有区别的在继承阶段会讲解。
3.访问权限作用域从该访问限定符出现的位置开始知道下一个访问限定符出现时为止如果后面没有访问限定符作用域就到 } 即类结束
4.上面我们提到了class和struct是有区别对于class其成员的默认访问权限为private而struct为public想想虽然在c中struct升级成了类但依然支持C语言struct的用法而C语言的struct成员都是可以直接被访问的不需要限定符。所以在这里struct的默认访问权限是public
注意访问限定符只在编译时有用当数据映射到内存后没有任何访问限定符上的区别
3.2封装
对于对象而言无非就三大特性封装、继承、多态。继承和多态后面的章节再说在类和对象阶段主要说的就是封装那么什么是封装呢
封装将数据和操作数据的方法进行有机结合隐藏对象的属性和实现细节仅对外公开接口来和对象进行交互封装本质上是一种管理让用户更方便实用类。说白了不就是用类将他们包起来再通过访问限定符是否对外提供接口来实现交互。
在现实中这个道理也是一样的像电脑里面的零件都是被封装的然后提供一个USB接口给用户使用。
四、类的作用域 在上面我们提到并给出了代码类中的函数长的声明和定义要分离分离定义的函数怎么与类中声明的函数进行联系呢跟命名空间一样类也是一个作用域类的所有成员在类的作用域中类外定义成员时需要使用::作用域操作 符指明成员属于那个类域 #include iostream
using namespace std;class Person
{
public://打印基本信息void printpersoninfo();
public:char _name[20];char _gender[3];int _age;
};//指明函数属于哪个类域
void Person::printpersoninfo()
{cout _name - _gender - _age endl;
}int main()
{Person s;strcpy(s._name , 李四);strcpy(s._gender , 女);s._age 19;s.printpersoninfo();return 0;
}
运行结果 五、类的实例化 仅仅有一个类不能对里面的内容进行访问而是要创建一个对象通过对象来对类中的成员进行访问。用类类型创建对象的过程称为类的实例化。 类是对对象进行描述的是一个模型一样的东西限定类有那些成员定义出一个类并没有分配实际的内存空间来存储它。必须实例化出对象才占有实际的物理空间存储类成员变量。且一个类可以实例化出多个对象。
比如房子设计图就是一个类设计图描述了房子的各种信息但是并没有为这些信息建造出一个实际的空间。而只有建造出了真正的房子才是实例化才分配了空间且通过设计图也可以建造出多个房子即实例化多个对象。再通过代码来比较。
#include iostream
using namespace std;class Person
{
public://显示基本信息void printpersoninfo();
public:char _name[20];char _gender[3];int _age;
};//指明函数属于哪个类域
void Person::printpersoninfo()
{cout _name - _gender - _age endl;
}int main()
{Person s;//创建对象且实例化多个对象Person t;Person u;strcpy(s._name , 李四);strcpy(t._name , 王五);strcpy(u._name , 李六);strcpy(s._gender, 女);strcpy(t._gender, 男);strcpy(u._gender, 男);s._age 18;t._age 19;u._age 20;s.printpersoninfo();t.printpersoninfo();u.printpersoninfo();return 0;
}
运行结果 六、类的对象大小的计算
6.1如何计算对象的大小 对于类中既有成员函数和成员变量那么计算大小时是不是他们都要算呢look #include iostream
using namespace std;
class A
{
public:void PrintA(){cout _a endl;}
private:char _a;
};int main()
{A a1;cout sizeof(a1);//猜猜多大return 0;
} 运行结果 通过结果发现大小只有1只计算了成员变量_a 的大小。这是怎么回事呢且看下面分析
6.2类对象的存储方式 以正常的理解当一个类实例化多个对象时对象与对象之间的成员变量、成员函数是互不干扰的但每个对象都会保存一份该成员函数的代码相同的代码保存了多份实例化了多份就会形成空间的浪费。 所以给了对象的新的存储方式对象中只保存成员变量而对于成员函数只保存一份放在公共代码区每个对象调用该函数时其实就是调用公共代码区的该函数。所以在上述计算大小时就不会算上成员函数。 再来看几个例子
空类
#include iostream
using namespace std;class A3
{};int main()
{cout sizeof(A3);return 0;
} 运行结果 为什么也是1呢不应该是0吗明明是一个空类。 OK空类其实也可以实例化对象这是前提。既然可以实例化对象那么对象就会在内存分配空间该对象有地址存在只不过不存储任何数据。如果空类的大小为0表示该类没有任何成员或对象。这意味着该类不占用内存空间。所以为了标识该对象存在编译器规定该空类的大小为1 类中仅有成员函数
#include iostream
using namespace std;class A2 {
public:void f2() {}
};int main()
{cout sizeof(A2);return 0;
}
运行结果 大小也是1根据上面的解释成员函数是放在公共代码区它们在内存中独立存在所以在计算大小时 相当于计算空类的大小。 注意计算类的大小依然遵守结构体内存对齐规则
七、类成员函数的this指针
7.1this指针的引出
#include iostream
using namespace std;class Date
{
public:void Init(int year 2023, int month 11, int day 23)//给缺省值{_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(2023, 1, 11);d2.Init(2023, 1, 12);d1.print();d2.print();return 0;
}
运行结果 对于上述类实例化两个对象在表面上两个对象都调用了Init函数时但是在深层函数怎么识别是谁调用 c引入了this指针来识别对象的调用c编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数让该指针指向当前对象函数运行时调用该函数的对象在函数体中所有“成员变量”的操作都是通过该指针去访问。但要注意的是this指针的所有操作对于程序员而言是透明的即this指针不需要程序员来传递编译器会自动完成可以认为是祖师爷设定好的。 7.2this指针的特性 1.this指针的类型类类型* const,例如Date* const this。由于this被const修饰所以在成员函数中不能给this指针赋值。 2.只能在“成员函数”的内容使用 3.this指针本质上是“成员函数”的形参当对象调用成员函数时将对象地址作为实参传递给this形参。所以对象本身不存储this指针。 4.this指针是“成员函数”第一个隐含的指针形参一般情况由编译器通过ecx寄存器自动传递不需要用户传递。 其实上述代码的本质就是第二张图的形式对应着上述规则。注意的是在调用函数传实参、以及函数的形参中不能显示的将this指针写出来否则会报错但在成员函数中可以显示的写出。
【面试题】
1.this指针存在哪里 将上述代码转到反汇编后可以发现d1对象和d2对象存放到rcx寄存器。由此this指针在VS下存放在栈区的寄存器中。
2.this指针可以为空吗
先看代码1下面运行结果 A、编译报错 B、运行崩溃 C、正常运行
#include iostream
using namespace std;class A
{
public:void Print(){cout Print() endl;}
private:int _a;
};int main()
{A* p nullptr;p-Print();return 0;
}
运行结果 答案是正常运行疑问的是p是空指针为什么可以访问Print函数 其实这是一个误区想想前面讲解的首先成员函数不是放在对象中而是在公共代码区其次在这里p并没有去访问Print函数但是如果没有访问该函数那又是怎么寻得该函数。在C语言中就知道了是在编译、链接阶段通过符号表来寻找函数名字所以在这里p的作用就是告诉编译器它属于A类然后在编译阶段A类中寻找是否存在Print函数。 代码2下面运行结果 A、编译报错 B、运行崩溃 C、正常运行
#include iostream
using namespace std;class A
{
public:void Print(){cout _a endl;}
private:int _a;
};int main()
{A* p nullptr;p-Print();return 0;
}
运行结果 运行结果是崩溃的对比第一个代码修改了成员函数的输出且成员变量并没有初始化。本质上就是this-_a这个就是空指针访问了成员变量而空指针并不指向任何有效的对象因此其中的成员变量也是未定义的。 综上所述虽然成员函数的代码本身放在公共代码区但成员函数通常涉及对对象中的成员变量进行操作这可能导致问题。因此最好不要让this指针为空以避免潜在的未定义行为。
end~
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87225.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!