前言
上一期我们介绍了一些C++入门的基础知识,本期我们来介绍面向对象。初步认识一下面向对象和面向过程、类、以及封装!
本期内容介绍
一、面向过程和面向对象
以前我也不怎么理解面向对象和面向过程!后来看到了很多例子后逐渐有了理解!我来举一个我以前理解最好的例子 --- 洗衣服。
当然还有其他同类的例子,例如把大象装到冰箱里面!
二、类的引入
C语言版本:
typedef int STDataType;
struct Stack
{
STDataType* a;
int top;
int capacity;
};
他的方法只能在外面!而C++就可以在里面!
C++版本:
#include <iostream>
typedef int STDataType;
struct Stack
{
STDataType* _a;
int _top;
int _capacity;
void Init(int capacity = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * capacity);
if (_a == nullptr)
{
perror("malloc failed");
exit(-1);
}
_capacity = capacity;
_top = 0;
}
//...
};
上述操作可以,但C++中更喜欢用class来替代struct
三、类的定义
class ClassName
{
//成员变量和成员方法(函数)
};//注意封号
类的两种定义方式
class Student
{
public:
//成员方法
void sleep()
{
cout << _name << "正在sleep()..." << endl;
}
private:
//成员属性
char* _name;
char* _sex;
int _age;
};
当然这里用struct也可以定义类!
成员变量的命名规则
四、类的访问限定符和封装
访问限定符
访问限定符的说明
OK, 举个栗子看看:
public(在类外可以访问,以属性举例,方法同理):
class Stack
{
public:
void Init(int capacity = 3)
{
_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
{
perror("malloc failed");
exit(-1);
}
_size = 0;
_capacity = capacity;
}
void Push(int x)
{
//...
}
int* _a;
int _size;
int _capacity;
};
int main()
{
Stack s;
s.Init();
cout << s._size << endl;
return 0;
}
这里把class直接换成struct也可以!
private/protectedd当前认为是一样的,在类外不可访问:
C++中struct和class的区别是什么?
注意:在C++中如果用struct定义结构体的话,在结构体类在申明结构体变量时,不用在+struct了
struct SLNode
{
int* data;
SLNode* next;
};
封装
五、类的作用域
class Date
{
public:
void Init(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Print();
private:
int _year;
int _month;
int _day;
};
//这里注意要指定Print属于Date这个类
void Date::Print()
{
cout << "999" << endl;
}
六、类的实例化
//类
class Date
{
public:
void Init(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;//实例化一个对象
d.Init(2023, 11, 25);
d.Print();
return 0;
}
1、类是描述对象的,是一个模型(模板),它限制了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储他。例如:开学时填写的学生信息表,这个表可以看成一个学生类,他来描述具体的学生(对象)!
2、一个类可以实例化多个对象,实例化出来的对象占用实际的物理空间,存储类成员变量
七、类对象模型
上面我们已经清楚了类的定义以及其实例化对象。一个对象有成员属性也有成员的方法,而我们想知道的是一个对象包含了什么?
OK,关于这个问题我就直接先说结论,再解释了:
我用一个我家鸽鸽的例子来说明:我家鸽鸽属于人这个类,他的名字和性别等是他个人独属于的!他的成员方法(行为)有:唱、条、rap、打篮球。但只有我家鸽鸽会唱、条、rap、打篮球吗?你是不是也可以啊,所以类的成员方法属于类!
class People
{
public:
//方法属于整个类
void Sing()
{
cout << "鸡你太美~..." << endl;
}
private:
//属性属于对象本身
char _name[20];
char _sex[5];
int age;
};
如何计算一个类的大小?
//既有成员变量又有成员方法的类
class A
{
public:
void Print()
{
//...
}
private:
int a;
};
//只有成员方法没有成员变量的类
class B
{
public:
void Print()
{
//...
}
};
//既没有成员变量有没有成员方法的类(空类)
class C
{
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
return 0;
}
结构体内存对齐规则(和C语言的一样):
如果这块还有问题,请点击后面的链接,这篇博文中我详细介绍过它的计算和栗子:
内存对齐
八、this指针
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 d1;
d1.Init(2023, 11, 25);
d1.Print();
Date d2;
d2.Init(2023, 11, 26);
d2.Print();
return 0;
}
Init和Print是类的成员方法,我们并没有指定是哪个对象的,为什么我们在调d1.Init的时候就是给d1对象赋值而不是给d2初始化呢?我们在d2.Print的时候是打印d2的属性的信息,为什么不打印d1会随机值呢????他到底是如何区别的呢?
this指针的特性
这应该是这里很坑的两个问题了,对基础考察很细!OK,我还是先说结论,再用栗子来解释!
OK,两个栗子分别解释一下:
栗子1:下列程序的编译运行的结果是?A、编译报错 B、运行奔溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
OK,他是C、正常运行!我们来看一下:
栗子2:下列程序的编译运行的结果是?A、编译报错 B、运行奔溃 C、正常运行
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
OK,这里是B、运行崩溃!
C语言和C++实现栈的对比
C语言
#include <assert.h>
typedef int DataType;
typedef struct Stack
{
DataType* array;
int capacity;
int size;
}Stack;
void StackInit(Stack* ps)
{
assert(ps);
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++:
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;
}