【本节目标】
1.面向过程和面向对象初步认识
2.类的引入
3.类的定义
4.类的访问限定符及封装
5.类的作用域
6.类的实例化
7.类的对象大小的计算
8.类成员函数的this指针
一、面向过程和面向对象初步认识
这里我们主要来介绍c语言和c++的区别,并且我会给其具体的例子
c语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用来逐步解决问题。
c++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成
例子 c语言:

c++:
#include<iostream>
#include<string>
using namespace std;
class Cake {
private:
string flavor; // 蛋糕的口味
int temperature; // 烤箱的温度
int time; // 烘烤的时间
public:
// 初始化蛋糕的属性
void setFlavor(string f) {
flavor = f;
}
// 自动计算烤箱的温度和时间
void calculateBakeSettings() {
if (flavor == "chocolate") {
temperature = 170;
time = 35;
}
else {
temperature = 180;
time = 30;
}
}
// 执行烘烤操作
void bake() {
cout << "正在以" << temperature << "度烘烤" << time << "分钟..." << endl;
}
};
int main() {
Cake chocolateCake;
chocolateCake.setFlavor("chocolate");
chocolateCake.calculateBakeSettings();
chocolateCake.bake();
return 0;
}

二、类的引入
我们知道在c语言结构体只能定义变量,但在c++中结构体内不仅可以定义变量,也可以定义函数
例如我们用c语言来定义栈的时候,结构体内只能定义变量,而我们用c++的时候我们就可以在struct内定义函数。
#include<iostream>
#include<string>
using namespace std;
typedef int DataType;//这里的用法很有必要这里我就先卖个关子
struct stack
{
void Init(int capacity) //初始化函数
{
array = (DataType*)malloc(sizeof(DataType) * capacity);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = capacity;
size = 0;
}
void push(const DataType& data) //扩容
{
array[size] = data;
++size;
}
DataType Top() //栈底元素
{
return array[size - 1];
}
void Destroy() //销毁
{
if (array)
{
free(array);
array = nullptr;
capacity = 0;
size = 0;
}
}
DataType* array;
int capacity;
int size;
};
int main()
{
stack s;
s.Init(10);
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
cout << s.Top() <<endl;
s.Destroy();
return 0;
}
在上面的用sturct结构体定义中,在c++中更喜欢用class来代替。
三、类的定义

class为定义类的关键字,className为类的名字,{}为类的主体,;不能省略
类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的和函数称为类的方法或者成员函数。
类的两种定义方式
1.全部放在类体中(如果成员函数在类中定义,编译器可能会将其当作内联函数处理)
class person
{
public:
void showperson()
{
cout << "打印成功" << endl;
}
public:
char* _name;//名字
char* _sex;//性别
int _age;//年龄
};
int main()
{
person s1;
s1.showperson();
}
2.类声明放在.h文件中,成员函数和放在.cpp文件中,注意:成员函数前要加类名::
//类声明放在 .h头文件中
class person
{
public:
void showperson();
public:
char* _name;//名字
char* _sex;//性别
int _age;//年龄
};
//定义实现放在.cpp文件中
#include "class.h"
void person::showperson()
{
cout << "打印成功" << endl;
}
int main()
{
person s1;
s1.showperson();
}
一般情况下我们使用第二种方式,但是为了方便我的后续代码的书写我一般是使用第一种演示方法
接下来我来给同志们一些成员变量名规则的建议
//我们来观察这个类会发现有没有有些地方很难懂
class Date
{
public:
void init( int year ) //这里我们的那个year是形参 那个year 是我们定义的成员变量
{
year = year;
}
private:
int year;
};
//上述的代码是不是很难区分,所以我们一般推荐下面的写法
class Date
{
public:
void init(int year) //这里我们的那个year是形参 那个year 是我们定义的成员变量
{
_year = year;
}
private:
int _year;
};
//或者
class Date
{
public:
void init(int year) //这里我们的那个year是形参 那个year 是我们定义的成员变量
{
Myear = year;
}
private:
int Myear;
};
四、类的访问限定符以及封装
4.1访问限定符
c++实现封装的方式:用类将对象的属性和方法封装在一块,让对象更加的完善,通过访问限定符选择性的将其接口提供给外部用户使用。
【这里我们需要对访问限定符进行一些说明】
1.public修饰的成员在类外可以被直接访问
2.protected 和private修饰的成员在类外是不可以被直接访问的(此处两者的用法是类似的)
3.访问权限的作用域是从该访问限定符的位置到下一个访问限定符出现为止
4.如果后面没有访问限定符,作用域就到 }结束
5.class的默认访问权限为private,struct为public(因为要兼容c)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有访问限定符上的区别
这里我们来给一道题
c++中struct和class的区别是什么
1.c++需要兼容我c语言,所以c++中的stuct可以当成结构体使用。
2.c++中的struct还可以定义类,这和class定义类是一样的,区别是struct定义的类是的默认访问权限的public,而class定义的类的默认访问权限是private。
3.注意:在继承和默认参数列表位置,struct和class也有区别
4.2 封装
面向对象的三大特性:封装、继承、多态。
在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口和对象进行交互
封装的本质是一种管理,让用户方便使用类,接下来我们来举一个例子来进行说明
五、类的作用域
class person
{
public:
void showperson();
private:
char* _name;//名字
char* _sex;//性别
int _age;//年龄
};
void person::showperson()//这里需要指定showperson是属于person这个类域
{
cout << "打印成功" << endl;
}
int main()
{
person s1;
s1.showperson();
return 0;
}
六、类的实例化
含义:用类类型创建对象的过程称为类的实例化
1类是对对象进行描述的,就像一个模型,限定了类有哪些成员,定义出一类并没有分配实际的类型空间来储存它;比如我们日常填写的表格就可以看做一个类,用来描述学生的具体信息
这里我们来举个例子来对类进行说明
谜语:“年纪不大,胡子一把,主人来了,就喊妈妈” 谜底:山羊
这里的谜语就像是类,而谜底就是 类实例出了的一个对象
2.一个类可以实例化出来很多对象 ,实例化出的对象才占用实际的物理空间,用来储存类的成员变量
class person
{
public:
void showperson()
{
cout << "打印成功" << endl;
}
private:
char* _name;//名字
char* _sex;//性别
int _age;//年龄
};
int main()
{
person .name;//错误的写发用类来访问了,因为类是没有空间的,只有实例化出的对象才有具体的名字
return 0;
}

3.我们这里来举个例子,类实例出来的对象就像用设计图来盖房子,类就像设计图,盖的房子就像类实例出来的对象。设计图是是不占空间的,房子就占了空间。
class person
{
public:
void showperson()
{
cout <<_age<< endl;
}
public:
char* _name;//名字
char* _sex;//性别
int _age;//年龄
};
void init()
{
person s1;
s1._age = 10;
s1.showperson();
}
int main()
{
init();
return 0;
}
七、类对象模型
7.1如何计算类对象大小
class A
{
public:
void print()
{
cout << _a << endl;
}
private:
int _a;
char _b;
};
int main()
{
A s1;
s1.print();//这里打印出来的值是随机值,为什么呢,同志们可以先自行探索一下,后边我会为解答
cout << sizeof(A) << endl;//这里运用了内存对齐的规则
cout << sizeof(s1) << endl;
return 0;
}
这里我们又会有一个问题,我们的类中不止有成员变量还有成员函数,为什么只计算了成员变量的内存而没有计算成员函数的内存呢?
这里我来直接回答同志们的这个问题:因为当我们使用类来定义对象的时候,实例出的对象的成员变量是不一样的,但是对我们每个对象调用的成员函数是相同的(所以我们把成员函数放在公共代码区即可)
class A
{
public:
void print()
{
cout << _a << endl;
}
private:
int _a;
char _b;
};
int main()
{
A s1;
s1.print();
A s2;
s2.print();
return 0;
}

通过反汇编我们可以看出这两个实例化出的对象调用print函数调用的都是同一个,说明成员函数是放在公共的代码段的,不占用类的内存空间
那么接下来我来出几道题同志们来做一下
class A
{
public:
void print()
{
cout << _a << endl;
}
private:
int _a;
char _b;
};
class B//仅有成员函数
{
public:
void print()
{
}
};
class C//空类
{
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;//空类是非常特殊的一个,编译器仅给一个字节来唯一标识这个类的对象
return 0;
}

结论;一个类的大小,实际就是类中成员变量之和,当然要注意的是内存对齐。
7.3结构体的内存对齐规则
八、this指针
8.1 this指针的引出
我们来首先定义一个日期类
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 s1;
s1.init(2025, 10, 15);
s1.print();
Date s2;
s2.init(2023, 10, 15);
s2.print();
return 0;
}
对于上述代码我们有一个问题:
Date 类中有print 和init两个成员函数,函数体内部并没有关于对象的区分那么当s1调用init函数时,该函数是怎么知道是s1调用的而不是s2调用的呢
这里c++通过引入了一个this指针来完成区分,即:
C++编译器给每个“非静态的成员函数“增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
8.2 this指针的特性介绍
1.this 指针的类型是:类类型是*const,即成员函数中,不能给this指针赋值
2.只能在成员函数的内部使用
3.this指针的本质是成员函数的形参,当对象调用成员函数时,将对象的地址作为实参传递给this形参,所以对象中不储存this指针。
4.this 指针是成员函数隐藏的一个形参,一般由编译器通过ecx寄存器自己传递,不需要用户传递
class Date
{
public:
/*void init(Date *this,int year, int month, int day)//形参传入this指针会报错的
{
_year = year;
_month = month;
_day = day;
}*/
void init( int year, int month, int day)
{
this->_year = year; // 但是我们可以在函数内部使用this来访问成员变量,但是我们一般不推荐这样写,麻烦
this->_month = month;
this->_day = day;
}
void print()
{
cout << this->_year << " " << this->_month << " " << this->_day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date s1;
s1.init(2025, 10, 15);
s1.print();
Date s2;
s2.init(2023, 10, 15);
s2.print();
return 0;
}
接下来给两道题目
1.this 指针存在哪里?
2.this 指针是否可以为空?
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
//正常运行,但是这里的p为空指针也会造成一些问题
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
//运行崩溃
class A
{
public:
void PrintA()//因为这里对空指针进行了解引用,因为我们要访问内置类型_a的值,
//就需要对this指针解引用,但是这里的this指针是空,所以就可能导致程序崩溃
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
改进方法

8.3 c语言和c++实现栈的区别
typedef int DataType;
typedef struct Stack
{
DataType* array;
int capacity;
int size;
}Stack;
void StackInit(Stack* ps)
{
assert(ps);//要包含头文件assert.h
ps->array = (DataType*)malloc(sizeof(DataType) * 3);
if (NULL == ps->array)
{
assert(0);
return;
}
ps->capacity = 3;
ps->size = 0;
}
void StackDestroy(Stack* ps)
{
assert(ps);
if (ps->array)
{
free(ps->array);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
}
void CheckCapacity(Stack* ps)
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity * 2;
DataType* temp = (DataType*)realloc(ps->array,
newcapacity * sizeof(DataType));
if (temp == NULL)
{
perror("realloc申请空间失败!!!");
return;
}
ps->array = temp;
ps->capacity = newcapacity;
}
}
void StackPush(Stack* ps, DataType data)
{
assert(ps);
CheckCapacity(ps);
ps->array[ps->size] = data;
ps->size++;
}
int StackEmpty(Stack* ps)
{
assert(ps);
return 0 == ps->size;
}
void StackPop(Stack* ps)
{
if (StackEmpty(ps))
return;
ps->size--;
}
DataType StackTop(Stack* ps)
{
assert(!StackEmpty(ps));
return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->size;
}
int main()
{
Stack s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
StackPush(&s, 4);
printf("%d\n", StackTop(&s));
printf("%d\n", StackSize(&s));
StackPop(&s);
StackPop(&s);
printf("%d\n", StackTop(&s));
printf("%d\n", StackSize(&s));
StackDestroy(&s);
return 0;
}
用c语言实现栈会麻烦一些
可以看到,在用C语言实现时,Stack相关操作函数有以下共性:
每个函数的第一个参数都是Stack*
函数中必须要对第一个参数检测,因为该参数可能会为NULL
函数中都是通过Stack*参数操作栈的
调用时必须传递Stack结构体变量的地址
这样写起来就比较麻烦
结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。
接下来让我们欣赏一下c++的实现方式
//c++的实现栈的方式
typedef int DataType;
class Stack
{
public:
void Init()
{
_array = (DataType*)malloc(sizeof(DataType) * 3);
if (NULL == _array)
{
perror("malloc申请空间失败!!!");
return;
}
_capacity = 3;
_size = 0;
}
void Push(DataType data)
{
CheckCapacity();
_array[_size] = data;
_size++;
}
void Pop()
{
if (Empty())
return;
_size--;
}
DataType Top() { return _array[_size - 1]; }
int Empty() { return 0 == _size; }
int Size() { return _size; }
void Destroy()
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
void CheckCapacity()
{
if (_size == _capacity)
{
int newcapacity = _capacity * 2;
DataType* temp = (DataType*)realloc(_array, newcapacity *
sizeof(DataType));
if (temp == NULL)
{
perror("realloc申请空间失败!!!");
return;
}
_array = temp;
_capacity = newcapacity;
}
}
private:
DataType* _array;
int _capacity;
int _size;
};
int main()
{
Stack s;
s.Init();
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
printf("%d\n", s.Top());
printf("%d\n", s.Size());
s.Pop();
s.Pop();
printf("%d\n", s.Top());
printf("%d\n", s.Size());
s.Destroy();
return 0;
}
这里我们可以发现以下优点
1.类中存放了数据和数据操作方式(即成员和函数),把类中的成员和成员函数封装在一起操作起来更方便。
2.用对象调用函数的时候只需要传入数据即可而不需要传对象的地址
3.成员函数的形参因为this指针的存在而变的非常简便
C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原,即C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护。



5890

被折叠的 条评论
为什么被折叠?



