中山手机网站建设电话,wordpress里面的附件如何导出,福建网站开发企业,国和建设集团网站有不少朋友会遇到这种情况#xff0c;在学完C入门的一些知识后#xff0c;就开始接触类和面向对象的概念#xff0c;大家去看书、文章的时候都会先抛出一大堆的概念#xff0c;导致我们听得很懵。那么这篇文章将言简意赅#xff0c;理解类和面向对象其实很简单#xff01… 有不少朋友会遇到这种情况在学完C入门的一些知识后就开始接触类和面向对象的概念大家去看书、文章的时候都会先抛出一大堆的概念导致我们听得很懵。那么这篇文章将言简意赅理解类和面向对象其实很简单
1. 面向对象与面向过程
其实很多学习编程的人对于面向过程编程和面向对象编程这两个概念总是搞不清具体的专业的定义在这里也不去说了根据上面的叙述我们可以这样去通俗的解释面向对象。
举个例子我去洗澡如果按照面向过程的角度考虑那么我先进入浴室然后打开水龙然后洗漱。然后把身体擦干也就是说面向过程关注的是解决问题的步骤如果用面向对象考虑只需记住一句话万物皆对象你是对象水龙头也是对象所以我先传递力的参数给浴室门然后门就开了然后我在传递消息给水龙头水龙头得到消息放水最后传递消息给毛巾毛巾利用它吸水的特性调用吸水方法擦干身体也就是说面向对象关注的是对象将一个问题拆分为不同对象依靠参数完成对象之间的交互。
为什么要进行面向对象编程这也是一个很值得思考的问题。举个例子活字印刷术发明之前使用的是雕版印刷这种方式弊端太大如果需要改稿那么雕版就必须重新雕刻而活字印刷术则解决了这样的问题。需要改动有可能只需改动几处。面向过程正如雕版印刷一样也正如做数学题一样中间某个环节—旦出现需求变更那么整个工程几乎需要大改要耗费大量时间精力。面向对像正如活字印刷术一样如果需求变化了。可能只是修改其中一部分也就是一个对象而且最关键的一点是这些对象可以复用进行活字印刷术一样。不是说这个对象在这个工程中发挥完之后它就没有价值了它还可能被其它工程所用。
2. 类的引入
学习C语言时我们知道结构体的作用是把一些具有不同类型的变量组合一起。
struct Student
{char _name[20];char _gender[3];int _age;
};
而在C中其结构体内不止可以定义变量而且还可以定义函数。
struct Student
{char _name[20];char _gender[3];int _age;void SetStudentInfo(const char *name,const char *gender,int age){strcpy(_name,name);strcpy(_gender,gender);_ageage;}
};int main()
{Student s;s.SetStudentInfo(Bob,男,18);return 0;
}
这样定义后结构体就可以被称为类只不过在C中我们更喜欢用class代替struct 。
其实我们在定义类的时候和定义结构体差不多只不过要记住名称换了而且类里面还可以定义函数。
3. 类的定义
3.1 C类的定义
根据以上叙述所以在C中是这样定义的
class className
{//成员函数//成员变量}//注意分号
所以简单来讲类就是属性和方法的集合属性就是类中的数据方法就是调用这些数据进行操作的函数。
3.2 类的两种定义方式
3.2.1 声明和定义全部都放在类体当中
要注意成员函数如果在类中定义编译器会将其当做内联函数处理。
class Person //人就是一个类
{public://成员函数void showInfo()//显示这个人的信息{std::cout_namestd::endl;std::cout_sexstd::endl;std::cout_agestd::endl;}public://成员变量char _name;char _sex;int _age;
};
3.2.2 定义和声明分开放
这种方式最常用。
// Person.hclass Person
{public:void showInfo();public:char* _name;char* _sex;int _age;
};
//Person.cpp#includePerson.hvoid Person ::ShowInfo()
{std::cout_namestd::endl;std::cout_sexstd::endl;std::cout_agestd::endl;
}
4. 类的访问限定符及封装
4.1 访问限定符
在前面类的定义中有一个 public 它属于访问限定符除了 public公开还有 private私密protected保护它们用于修饰成员比如 public 修饰的成员可以在类的外面直接被访问而是用 protected 和 private 修饰的在类的外面不可以直接被访问。 注意以下几点
访问限定符的作用域是从该访问限定符出现的位置开始直到下一个访问限定符为止 class的默认访问权限就是没有给出为 privatestruct 则为public访问限定符限制的是外面就像锁子防的是外人 4.2 封装
我们知道面向对象三大特性封装继承多态
封装本质是一种管理手段。将属性数据和方法接口有机结合起来再隐藏他们只对外公开接口(函数)来和对象进行交互。不想给别人看的使用 protected/private 进行修饰而开放一些公有函数对成员进行合理访问合理访问可以理解为阅读不合理访问可以理解为改写(不准确)。
这里也就能说明为什么C语言不支持大型项目的编写因为它不支持面向对象管理能力较弱不是函数就是数据就拿 struct 来说其默认就是 public 的安全性也堪忧总的来说用C语言编写项目会感觉很乱模块与模块独立性很差。
之前使用C语言实现过很多数据结构比如说栈我们都是新建一个工程然后分别建立它的声明。实现等文件也就是说数据和方法是分离的是自由的如果换到C中按照面向对象考虑一个栈就可以作为一个对象这个对象有它的数据动态增长的数组长度容量还有它的方法栈的初试线压栈。出栈等等。像这些数据应该就是私有的因为要防止外部操作改变数据一旦数据出错那么方法也就会受到相应的波及然后这些操作按照实际需求让外部使用。
如
//stack.h
class Stack //类
{
public:void Init(int capacity4); //缺省参数声明private:int *_arr;int _length;int _capacity;};//stack.cpp
void Stack::Init(int capacity)//该方法的实现
{_arr(int *)malloc(sizeof(int )*capacity);_length0;_capacitycapacity;
};
5. 类的实例化
5.1 类的实例化
类可以理解为一个房屋的图纸这个图纸规定了一些基本信息比如说这个房子朝向是什么。有几扇庶户。房子材料是什么等等。但是图纸终归就是图纸纸上谈兵永远不会成为现实要把这个图纸现实化就要根据这个图纸的规定修出相应的房子。当然,不按照图纸也能修只不过修出来的房子可能成为四不像或者不安全。这也就像C语言没有图纸接口随意写数据任你改是很自由但是稍有不慎房子就可能用不久了。
所以说根据图纸建造房子的过程称为类的实例化就像前面的栈一样实例化出一个真正的栈什么叫做真正的栈--这个栈它占用实际空间。一个图纸不可能只能造出一个房子而是可以造出千千万万个房子这个诸多房子本原都是一个要想让他们之间有所区别这取决于使用者比如你和我都按照这个图纸了建造了相同的房子但是我们对房子的装饰不同所以看起来也就像两个不同的房子。回到栈我们可以实例化出许许多多的栈但是有些栈用于进行非递归操作有些栈用于排序操作他们就不是一样的了。
比如前面的栈可以实例化为
//stack.h
class Stack //类
{
public:void Init(int capacity4); //缺省参数声明private:int *_arr;int _length;int _capacity;};//stack.cpp
void Stack::Init(int capacity)//该方法的实现
{_arr(int *)malloc(sizeof(int )*capacity);_length0;_capacitycapacity;
};//test.cpp
int main()
{Stack stack;stack._arr4;//操作非法成员是 privatae 的stack.Init();//初始化这个栈
}
6. 类对象模型
6.1 如何计算类对象的大小
下面这个类实例化后所占的空间大小
class A
{
public:void print A{std::coutastd::endl;}private:char _a;
};
猜测结合之前学习C语言学习结构体内存对齐这个类中成员变量和成员函数其中 char 占用一个字节成员函数实际是一个函数地址所以在32为平台下一个指针占用4个字节所以总共是5个然后根据内存然后占用8个究竟是不是这样可以执行。 结构显示只有一个字节不是预想的8个字节再次观察这个类也能想到类在计算大小时不管成员函数只管成员变量和内存对齐。
那么成员函数究竟在哪
6.2 类对象的储存方式
根据以上叙述不禁会提出一个问题为什么成员函数不在类内
其实一个类可以实例化很多对象就拿栈来说这些栈它储存的数据可能不一样但他们的方法进栈出栈都是一样的所以在实例化时如果为他们再开辟空间就会造成浪费。
所以解决方法是只保存成员变量成员函数存放到公共的代码段内常量区 注意一般情况下一个类的大小 实际就是该类中成员变量和成员对齐但是要注意空类空类大小不是0编译器提供了一个字节表示它存在。 7. this指针
7.1 一个问题
定义一个日期类
class Date
{public:void SetDate(int year,int month,int day){_yearyear;_monthmonth;_dayday;}private:int _year;int _month;int _day;
}int main()
{Date d1;Date d2;d1.SetDate(2021,2,20);d2.SetDate(2024,7,10);
}
上述代码中看起来没有问题。但是容易忽略一个细节类中成员函数是公用的它并不存在于类中那么 d1.SetDate(2021,2,20编译器怎么会知道要给d1这个类去设置而不会给d2去设置。这里很多有疑问不是函数前面已经写了一个 d1 吗这里大家一定要跳出这个误区函数只是放在了公用的代码段如果函数是放在类里的那无可厚非。但是当放在公用的代码段后不要说用实例化的类去调用它就是我先如果知道函数的地址的话用汇编都可以去调用那么当无数个类去调用这个函数时编译器怎么会分的这么清楚。
7.2 this指针
这个问题在C中是通过引入this指针来解决的。官方定义C编译器给每个非静态的成员函数增加了一个隐藏的指针参数。让该指针指向当前函数运行时调用该函数的对象在函数体中所有成员变量的操作都是通过该指针操作。
所以如果上述代码写完整应该是下面这样的
class Date
{public:void SetDate(Date* this,int year,int month,int day){//生成一个类指针this-_yearyear;this-_monthmonth;this-_dayday;//通过指针的指向来辨别对象}private:int _year;int _month;int _day;
}int main()
{Date d1;Date d2;d1.SetDate(d1,2021,2,20);d2.SetDate(d2,2024,7,10);//所以参数里实际就是函数的指针
}
7.3 this指针存在那里
这是一个极高频率的面试题
谈及C、C的内存开辟就不得不上这样一张图了 this指针是作为一个函数隐藏的形参而栈是存放局部变量形参的。所以this指针存在于栈中。还有一个经典的题如下这段程序是否会崩溃
class A
{public:void printA(){ std::cout_astd::endl;}void show(){std::coutshowstd::show;}private:int _a;};int main()
{A*pNULL;p-printA();p-show();
}
这段程序的结果是如果只执行 p-printA() 就会崩溃如果只执行 p-show() 就不会崩溃。
如下 仔细分析未免让人觉着有点匪夷所思 A* pNULL 表明p是一个空的类指针那么既然是空的就不能对空指针进行操作但是观察上述两种情况 p→printA(报错了 p→show(并没有报错。其实原因就是在于这this指针首先对于 show(和 printA()来说他们不存在与类内而存在于公共的代码段内所以使用指针 ρ 进行这样的操作并不是在取成员所以问题不在于空指针。
问题在于调用 printA() 时将这个 p 指针作为 this 指针传了过去那么在函数中就会进行std::coutthis→_astd::endl的操作自然而然会出现问题而另一个函数没有崩溃是因为它就没有使用到这个 this 指针。 这篇文章对类和面向对象的相关知识点进行了梳理。欢迎大家评论交流