类和对象(一)
C++并不是纯面向对象语言
C++是面向过程和面向对象语言的!
面向过程和面向对象初步认识:
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完
成。
//C++兼容C兼容C结构体用法 typedef struct list { int data; struct list* next; }Li; //C++中会把C中的结构体升级为类 struct listnode { int data; listnode* next; };//这里不需要重命名变量名称,直接可以使用
C++中(.cpp文件),next可以直接用listnode来命名,而C语言中(.c文件),next不可以直接listnodei*来命名。
类中不止可以放变量名,还可以存放函数。
struct listnode { void Init(int n) { data = n; next = NULL; } int data; listnode* next; }; int main() { //类和对象 listnode* l; l->Init(5); return 0; }
上面结构体的定义,在C++中更喜欢用class来代替。
类的定义:
class className { // 类体:由成员函数和成员变量组成 }; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分
号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。
类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
访问限定符:
访问限定符分为三种:public、protected、private
【访问限定符说明】
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
class stack { public: int a; int c; protected: char b; private: double f; };
我们是否可以在类外访问private类型参数?
不可以,因为这里是私有,所以会报错
C++中struct和class的区别是什么?
struct定义类默认访问限定符为public
解答:C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来
定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类
默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序给大
家介绍。
class Date { public: void Init(int year, int month, int day) { year = year; } private: int year; int month; int day; }; int main() { ///编译不会出错,但是并不会赋值 Date d1; d1.Init(2023, 3, 7); return 0; }
当成员变量与类中函数参数名相同时,是否会报错?
这里函数参数和成员变量相同,因为局部变量优先,因此不会初始化。-
因此我们如果遇到相同的变量名,我们会在其中一个变量名前面加一个_
this指针:
当定义了两个对象d1,d2,我们的成员函数Init怎么知道我们定义的是哪个对象呢?
class Date { public: void Init(int year, int month, int day) { _year = year; } private: int _year; int _month; int _day; }; int main() { Date d1; Date d2; d1.Init(2023, 2, 3); d2.Init(2023, 2, 3); return 0; }
编译器会悄悄地帮你多加一个参数来实现区分
通过this这个关键字来实现,这是编译器默认加,我们并不允许在参数or调用时主动加这个东西
this指针存在哪里?
并不是存在对象里面,存在栈上,因为它是隐含的形参
vs下面是通过ecx寄存器
this空指针问题:
下面这两句的运行结果
Date* ptr = nullptr; ptr->func();//正常运行 //func和init不在对象里面,而是call到公共区域(代码段)找 //会不会报错取决于需不需要去变量里面找,而不是解引用符号 ptr->Init(2022, 2, 2);//崩溃
func和init不在对象里面,而是call到公共区域(代码段)找
会不会报错取决于需不需要去变量里面找,而不是解引用符号
(*ptr).func();//正常运行
类的内存大小:
类的内存大小如何算呢?
类的内存大小可以参考C语言中结构体的计算方法。
class Date { public: void Init(int year, int month, int day) { year = year; } private: int year; int month; int day; }; int main() { //类和对象 Date d1; Date d2; cout<< sizeof(d1) << endl;//12 return 0; }
为什么成员变量在对象中,成员函数不在对象中呢?
每个对象成员变量是不一样的,需要独立存储
每个对象调用成员函数是一样的,放到共享区域(代码段)
int main() { //类和对象 Date d1; Date d2; cout<< sizeof(d1) << endl;//12 //为什么成员变量在对象中,成员函数不在对象中呢? //每个对象成员变量是不一样的,需要独立存储 //每个对象调用成员函数是一样的,放到共享区域(代码段) d1.Init(2023, 3, 7); d2.Init(2022, 2, 2); return 0; }
因此我们计算类的大小,就需要计算变量的内存大小,不用考虑成员函数,因此跟结构体的算法一样的
Date d1; Date d2; cout<< sizeof(d1) << endl;//12 //为什么成员变量在对象中,成员函数不在对象中呢? //每个对象成员变量是不一样的,需要独立存储 //每个对象调用成员函数是一样的,放到共享区域(代码段) d1.Init(2023, 3, 7); d2.Init(2022, 2, 2); return 0;
}
因此我们计算类的大小,就需要计算变量的内存大小,不用考虑成员函数,因此跟结构体的算法一样的