【C++入门】面向对象(1)
目录
在开始之前,问各位读者一个问题,把大象关进冰箱,需要几步?传统关大象是:
①打开冰箱门;②把大象放进冰箱;③关上冰箱门;这就是面向过程;那么面向对象怎么关大象呢?
①将大象封装成一个类,将冰箱封装成一个类;
②冰箱类使用open方法,打开冰箱门;
③大象类使用in方法,进入冰箱;
④冰箱类使用close方法,关闭冰箱。
这就是面向对象。
1.初步认识面向对象
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题;
C++是面向对象的,关注的是对象,将一件事情拆分为不同的对象,靠对象之间的交互完成。
2.类的定义
类的定义非常简单,class后面直接跟类名,类体中可以写成员变量和成员方法。
类中的元素可以称之为类的成员;类中的数据可以称之为类的属性;类中的函数可以称之为类函数或者成员函数。
class className
{
// 成员变量 + 成员方法
};
2.1 类的两种定义方式
①函数一般在类内声明+实现,只在类中声明会导致会让编译器误认为是内联函数。
②类的声明,类内函数的声明都在头文件,类内函数的实现,在cpp文件中实现。

2.2 结构体&类
在c语言中,结构体的指针定义需要加上struct,并且不能在结构体内定义函数;
在c++中,结构体的指针定义更加简略,可以在结构体中定义成员函数,和类的使用基本一致。
在c++中,class和struct的区别在于默认的访问限定符不一样,struct默认是公有,而class默认是私有。
struct ListNode_c
{
int val;
struct ListNode* next;
struct ListNode* prev;
};
struct ListNode_cpp
{
int val;
ListNode* next;
ListNode* prev;
// 可以定义函数->成员函数
};
3.类的访问限定符以及封装
类内的元素可以设置访问限定符让类外的访问受到限制,使用访问限定符就可以做到这一点,如果你不想让你的类元素被外界访问,那么可以使用private和protected。

例如下面的例子:外部只能访问public作用域的部分。

类如果不使用访问限定符,默认是私有的;结构体默认是公有的。在C++中可以使用struct,跟类的使用方法一样。
4.类的实例化
我们可以把类的定义当做一个图纸,那么类的实例化就是根据这个图纸造出来的具体的房子。此时类的实例化才会真正占用空间。
#include<iostream>
class Person
{
char name[20];
char gender[2];
void goSleep();
};
// 类内声明,类外实现
void Person::goSleep()
{
std::cout << "I am going to sleep" << std::endl;
}
int main()
{
Person zsan; // 创建对象
}
将对象的大小进行查看,发现对象只存储成员变量,不存储成员函数。这是因为不同的对象调用的函数都是同一个函数,函数是写死的,如果一个对象一个函数,会浪费存储空间。

所以如果要计算类对象,只需要将成员变量相加即可,并考虑内存对齐规则。
class A1
{
int _a;
char _b;
};
class A2
{
public:
void func();
};
class A3
{
};
int main()
{
A1 a1;
A2 a2;
A3 a3;
cout << sizeof(a1) << endl;
cout << sizeof(a2) << endl;
cout << sizeof(a3) << endl;
}
没有成员变量的类的大小规定为1;a1为什么是8呢,如果不了解的读者,可以去看看写者主页C语言篇章中结构体内存对齐的部分。这里大概讲一下,a占用4个字节,vs默认最大对齐数是8,二者取小,所以a的最大对齐数是4,b同理,最大对齐数是1,所以整体字节数就是5个,那么这两个元素中最大的对齐数是4,所以整体字节数必须是最大对齐数的倍数,并且能存下5个字节。所以是8。

这里开辟一个字节的空间是为了让对象有一个地址,如果不给空间,那么就没有地址。
5.this指针
下面写一段代码,存在两个问题:
①在初始化函数中,我们如何区分形参和成员函数;
②在打印函数中,我们为什么能够直接使用成员函数;
#include<iostream>
using namespace std;
class Date
{
private:
int year;
int month;
int day;
public:
void InitTime(int year,int month,int day)
{
// 这里的形参和类内的参数如果名称相同,那么如何传参
}
void printDate()
{
cout << year << "-" << month << "-" << day << endl;
}
};
答案就是this指针,在print函数的形参列表中,虽然是空的,但是在编译的时候,会增加一个叫类指针的东西,这个指针叫this指针,是本类的指针,我们可以直接通过这个指针访问类的成员变量。
在调用的时候,虽然在实参列表中也没有传入,任何的值,实际上传入了对象的地址。

5.1 面试题
5.1.1 this指针存在进程地址空间的哪个区域?
存在栈中,因为this作为形参使用;在vs里面存入ecx寄存器里。面试直接就说存在栈中,

5.1.2 this指针可以为空吗?
看下面代码,看看注释的那两行是否会出现问题。

第一行:
空指针问题如果能在编译中检查出来,那就不会引发空指针问题了,所以对于空指针的解引用,最后导致的结果一定是崩溃,而不是提前在编译下检查出来。
第二行:
能够正常运行, 这是因为如果要访问成员函数,那么不需要使用对象或者对象指针,因为函数是直接存储在代码区中的,那么如果需要访问成员变量,这样一来就会出现问题,例如PrintA函数中访问了成员变量,此时就会使用对象指针进行解引用,此时就会遇到空指针的问题。

更多推荐
所有评论(0)