目录
一、面向过程和面向对象初步认识
二、类的引入
命名规则
三、类的定义
四、访问限定符
五、类的作用域
六、类的实例化
七.类对象模型
一、面向过程和面向对象初步认识
1.C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
2. C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完
成。
以洗衣服为例子
c语言关注
c++关注
二、类的引入
鉴于C++面向对象的特点,于是就创建出类这个概念来处理每个对象,我们可以通过类来描述每个对象的全部特点
但是虽然c++是基于面向对象的语言,关注对象,但是它也支持面向过程,因此c语言和c++的代码可以混编
c++兼容c语言,结构用法可以继续使用
同时struct也升级成了类
struct Stack//类名
{int* a;int top;int capacity;
};int main()
{struct Stack st1;//结构体的用法Stack st2;//类的用法,类名可作类型
};
同时,类中不止可以定义变量,也可以声明和定义函数
不用我们主动传参,成员函数可以直接访问成员变量,例子如下
typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}DataType* _array;size_t _capacity;size_t _size;
};
int main()
{Stack s;s.Init(10);return 0;
}
命名规则
为了避免函数形参与成员变量之间产生混淆等 ,我们一般将成员变量加上标记处理,比如_,my等等。如果形参与成员变量名称相同,默认优先使用局部域的变量,就会形成局部变量自己赋值给自己的情况
class Date
{
public:void Init(int year){_year = year;}
private:int _year;
};
// 或者这样
class Date
{
public:void Init(int year){mYear = year;}
private:int mYear;
};
三、类的定义
但是c++中更喜欢使用class,主要原因在4.访问限定符中讲
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器会将其当成内
联函数处理。
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
,因为编译器遇到一个变量要去找,加了类名它才知道去哪找,不加类名它只会默认在全局去找
一般情况下,更期望采用第二种方式
四、访问限定符
C++实现封装的方式:
用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
【访问限定符说明】
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 } ,即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C),因此我们在c++中更喜欢使用class
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
一般来说我们习惯将成员变量私有,通过公有的成员函数进行访问,同时,类里面不受访问限定符的限制
五、类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域。
class Person
{
public:void PrintPersonInfo();
private:char _name[20];char _gender[3];int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{cout << _name << " "<< _gender << " " << _age << endl;
}
我们可以将花括号就看成一个域的界限
六、类的实例化
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 d;//这里开了空间,这才叫定义return 0;
}
那三个成员变量都绑在一起定义了, 对象的定义也叫做对象的实例化。
同样的,函数的定义和声明也是一样,定义需要分配存储空间;声明只是告诉编译器这个函数已经在别处定义过了。
函数的定义和声明比较好区分。有函数体的即为定义,不带函数体即为声明。
七.类对象模型
接下来再看另一个问题
int main()
{date d1;d1.init(2024,7,12);d1.Print();d1._year;date d2;d1.init(2024,7,13);d1.Print();d2._year;
}
我们sizeof(date) 与sizeof(d1)得出的值均为12(实际上,sizeof计算对象的大小也是转换成对对象类型的计算)
我们知道,d1中的_year 与d2中的_year不是一个变量,但是d1中的Print()与d2中的Print()是同一个函数,如果我们在每个对象中都存一个,这种方式不划算。所以d1.year 与d2._year是到对象里面去找,但是d1.Print()与d2.Print()是到公共的代码区去找。成员函数与全局函数都储存在公共代码区
因此一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
// 类中什么都没有---空类
class A
{};