面向对象和面向过程究竟有何区别?简单的说一句:
C语言是面向过程的语言,关注的是过程,分析问题求解的步骤,通过函数调用解决问题。
c++语言是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,通过对象之间的交互完成。
这只是简单的总结,我们会一步一步去认识清楚何为面向对象,今天先让我们走进c++的类和对象吧~~~
c++中引入了类和对象,那么什么是类和对象呢?
我们想象生活中的例子:如今我们的生活最基本的需求,那应该就是一个漂亮的房子了吧~~~~那么我们想想,满足我们这么多人的需求,开发商就需要建造成千上百栋的房子,那么建造房子需要什么呢?答案当然是【图纸】了,只有先把图纸规划好,然后才能开始动工建造漂亮的房子。
这个例子就正好和我们的类和对象一致:图纸就相当于我们定义的类,而房子就是我们实例化出来的对象;只需要一张图纸,就可以建造很多房子,那么同理,只需要定义一个类,就可以实例化出多个对象。
看完枯燥的句子,让我们换一下心情,上一个例子看看:
类的声明放在.h文件中,类的定义放在.cpp文件中
mian.h文件
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <iostream>
using namespace std;
#include <string.h>
//定义类【class 可以用 struct】
class Student
{
public:
void SetStudentInfo(const char *name, const char *gender, int age);//声明函数
void PrintStudentInfo();//声明成员函数
private:
char _name[20];//定义成员变量
char _gender[3];//定义成员变量
int _age;//定义成员变量
};
test.cpp文件
#include "main.h"
void Student::SetStudentInfo(const char *name, const char *gender, int age)//定义成员函数
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void Student::PrintStudentInfo()//定义成员函数
{
cout << _name << " " << _gender << " " << _age << endl;
}
int main()
{
Student s1, s2, s3;//实例化出三个对象
s1.SetStudentInfo("小明", "男", 20);
s2.SetStudentInfo("小张", "男", 21);
s3.SetStudentInfo("小黄", "女", 22);
s1.PrintStudentInfo();
s2.PrintStudentInfo();
s3.PrintStudentInfo();
system("pause");
return 0;
}
C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。
类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需要注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处 理。
2. 声明放在.h文件中,类的定义放在.cpp文件中【建议第二种,因为一般如果成员函数声明和定义都在类内,并且函数内没有循环或递归,则会被当成内联函数处理】
现在我们对于类和对象有了初步认识,那么就进入到我们的重点:访问限定符以及封装
何为封装?
封装就是:将数据和操作数据的方法有机的结合在一起,隐藏对象的属性和实现细节,仅仅对外公开接口来和对象进行交互。
c++实现封装的方式:用类把对象的属性和方法结合在一块,让对象更加的完善,通过访问权限选择性的将对象的接口提供给外部用户使用。
何为访问限定符?
【访问限定符说明】
1. public修饰的成员在类外可以直接被访问2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
类的作用域?
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符 指明成员属于哪个类域【实例参照上述的例子】
类的对象存储模型?
问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大 小?
要解决这个问题,首先要知道:类对象是如何在内存中存储的【提出三种假设存储方式】
那么现在我们就来验证一下看看对象模型在内存中是如何存储的?
#include <iostream>
using namespace std;
class A
{
public:
void PrintInfo()
{
cout << t << endl;
}
private:
int t;
};
class B
{
public:
void PrintInfo()
{
cout << "lala" << endl;
}
};
class C
{
};
int main()
{
cout << sizeof(class A) << endl;
cout << sizeof(class B) << endl;
cout << sizeof(class C) << endl;
system("pause");
return 0;
}
那么现在让我们来看看结果是什么?
结果很清晰,我们发现:类的大小计算【vs、linux下】 一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
现在我们知道了:对象的存储就是按第三种存储方式进行存储的
那么方式一的缺陷是什么?
缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多 个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间
方式二的存储方式我们后面会提到~~~
现在让我们关注一个重要的话题,那就是this指针,他究竟有何秘密呢?
先让我们来看看用C语言写的一段代码:
typedef struct Stuent
{
char _name[20];
char _gender[3];
int _age;
}Stuent;
void SetStudentInfo(Stuent *s, const char *name, const char *gender, int age)
{
strcpy(s->_name, name);
strcpy(s->_gender, gender);
s->_age = age;
}
void PrintStudentInfo(Stuent *s)
{
printf("%s ", s->_name);
printf("%s ", s->_gender);
printf("%d \n", s->_age);
}
int main()
{
Stuent s4, s5, s6;
SetStudentInfo(&s4, "小明", "男", 20);
SetStudentInfo(&s5, "小张", "男", 21);
SetStudentInfo(&s6, "小黄", "女", 22);
PrintStudentInfo(&s4);
PrintStudentInfo(&s5);
PrintStudentInfo(&s6);
system("pause");
return 0;
}
接着让我们用c++语言代码来比较一下:
#include "main.h"
void Student::SetStudentInfo(const char *name, const char *gender, int age)//定义成员函数
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void Student::PrintStudentInfo()//定义成员函数
{
cout << _name << " " << _gender << " " << _age << endl;
}
int main()
{
Student s1, s2, s3;//实例化出三个对象
s1.SetStudentInfo("小明", "男", 20);
s2.SetStudentInfo("小张", "男", 21);
s3.SetStudentInfo("小黄", "女", 22);
s1.PrintStudentInfo();
s2.PrintStudentInfo();
s3.PrintStudentInfo();
system("pause");
return 0;
}
我们不难发现,c++语言代码的成员函数参数个数比C语言代码函数参数个数少一个,少的就是C语言函数第一个参数,怎么会出现这样的情况呢?
其实真相很简单,c++语言中成员函数参数并没有少第一个参数,只是被编译器隐藏起来了而已,在c++中成员函数的第一个参数就是this指针,不过我们并看不见它,它是由编译器在底层暗暗地操作着,指向要指向的对象。
C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指 针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访 问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性
1. this指针的类型:类型 * const2. 只能在“成员函数”的内部使用
3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this 形参。所以对象中不存储this指针。
4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递