#include<iostream>
#include<assert.h>
using namespace std;
class Stack
{
public:
void Init(int n = 4)
{
array = (int*)malloc(sizeof(int) * n);
if (array == nullptr)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
void Push(int x)
{
//...扩容
array[top++] = x;
}
int Top()
{
assert(top > 0);
return array[top - 1];
}
void Destroy()
{
free(array);
array = nullptr;
top = capacity = 0;
}
private:
int* array;
size_t capacity;
size_t top;
};
//C++兼容C语言中的struct,同时struct也升级成了类
struct Person
{
public:
void Init(const char* name, int age, int tel)
{
strcpy(_name, name);
_age = age;
_tel = _tel;
}
void Print()
{
cout << "姓名:" << _name << endl;
cout << "年龄:" << _age << endl;
cout << "电话:" << _tel << endl;
}
private:
char _name[10];
int _age;
int _tel;
//...
};
typedef struct QueueNode
{
struct QueueNode* next;
int val;
}QNode;
typedef struct Queue
{
Queue* head;
Queue* tail;
int size;
}QU;
void QueueInit(QU* q)
{
q->head = nullptr;
q->tail = nullptr;
q->size = 0;
}
int main()
{
//类名就是类型,用类型定义对象
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
cout << st.Top() << endl;
st.Destroy();
Person p1;
p1.Init("张三",18,12345);
p1.Print();
p1.age++;//报错
QU qu;
QueueInit(&qu);
return 0;
}C++中class定义类相比于C语言中struct结构体的区别:

//具体让什么公有什么私有取决于自己,一般成员函数设为公有,成员变量设为私有,
//因为成员变量不希望被改变,私有的在类外不能用,在类内成员函数能用
#include<iostream>
#include<assert.h>
using namespace std;
class Stack
{
public:
void Init(int n = 4)
{
array = (int*)malloc(sizeof(int) * n);
if (array == nullptr)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
void Push(int x)
{
//...扩容
array[top++] = x;
}
int Top()
{
assert(top > 0);
return array[top - 1];
}
void Destroy()
{
free(array);
array = nullptr;
top = capacity = 0;
}
private:
int* array;
size_t capacity;
size_t top;
};
int main()
{
//类名就是类型,用类型定义对象
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
cout << st.Top() << endl;
st.Destroy();
return 0;
}比较短小的函数就在类里面去定义,默认是内联函数,长一点的函数不在类里面去定义在类外面去定义,在.cpp文件里面去定义,做函数声明和定义的分离。下面展现的就是标准的类的声明和定义分离。
Stack.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Stack
{
public:
void Init(int n = 4);
private:
int* _array;
int _top;
int _capacity;
};Stack.cpp
#include"Stack.h"
//声明和定义分离需要指定类域
void Stack::Init(int n)
{
_array = (int*)malloc(sizeof(int) * n);
if (_array == nullptr)
{
perror("malloc file!");
return;
}
_capacity = n;
_top = 0;
}Test.cpp
#include"Stack.h"
int main()
{
Stack st;
st.Init();
return 0;
}成员变量是声明,不是定义,声明不开辟空间,定义开辟空间。
#include<iostream>
using namespace std;
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 year;
int main()
{
//类实例化出对象,1->N的关系,类里面不能存储数据
Date d1;
Date d2;
d1.Init(2024, 9, 22);
d2.Init(2024, 9, 23);
d1.Print();
d2.Print();
return 0;
}分析一下类对象中有哪些成员呢?类实例化出的每个对象,都有独立的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?
首先函数被编译后是一段指令,对象中没办法存储,这些指令存储在一个单独的区域(代码段),如果对象中非要存储的话,只能是成员函数的指针。再分析一下,对象中是否有存储指针的必要呢?Date实例化d1和d2两个对象,d1和d2都有各自独立的成员变量_year/_month/_day存储各自的数据,但是d1和d2的成员函数Init/Print指针却是一样的,存储在对象中就浪费了。如果Date实例化出100个对象,那么成员函数指针就重复存储100次,太浪费了。这里需要再说一下,其实函数指针是不需要存储的,函数指针是一个地址,调用函数被编译成汇编指令[call地址],其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址,这个我们后面讲解。
上面我们分析了对象只存储成员变量,C++规定类实例化的对象也要符合内存对齐的规则。
内存对齐规则
#include<iostream>
using namespace std;
// 计算⼀下A/B/C实例化的对象是多⼤?
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
}
//对于没有成员变量的类对象,开1个字节,占位,不存储有效数据
//表示对象的存在
class B
{
public:
void Print()
{
//...
}
}
class C
{};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}
上⾯的程序运⾏后,我们看到没有成员变量的B和C类对象的⼤⼩是1,为什么没有成员变量还要给1个字节呢?因为如果⼀个字节都不给,怎么表⽰对象存在过呢!所以这⾥给1字节,纯粹是为了占位标识对象存在。
#include<iostream>
using namespace std;
//编译器自己回加上this,我们不必加上
class Date
{
public:
//void Init(Date* const this, int year, int month, int day)
void Init(int year, int month, int day)
{
//this->_year = year;
_year = year;
_month = month;
_day = day;
}
//void Print(Date* const this)
void Print()
{
//this = nullptr;this不能被修改,但是this指向的内容可以被修改
cout << this->_year << '/' << _month << '/' << _day << endl;
}
private:
//声明
int _year;
int _month;
int _day;
};
//定义
int year;
int main()
{
Date d1;
Date d2;
//d1.Init(&d1,2024,9,20)
d1.Init(2024, 9, 20);
//d2.Init(&d2,2024,9,22)
d2.Init(2024, 9, 22);
//d1.Print(&d1);
d1.Print();
//d2.Print(&d2);
d2.Print();
return 0;
}【 习题三道】
1.下⾯程序编译运⾏结果是(C)
A、编译报错 B、运⾏崩溃 C、正常运⾏
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
}
int main()
{
A* p = nullptr;
p->Print();
return 0;
}2.下⾯程序编译运⾏结果是(B)
A、编译报错 B、运⾏崩溃 C、正常运⾏
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}【分析】

3. this指针存在内存哪个区域的 (A)
A. 栈 B.堆 C.静态区 D.常量区 E.对象⾥⾯
this是一个隐含的形参。局部变量,形参存在函数栈帧里面。
面向对象三大特性:封装、继承、多态,下面我们来初步了解一下封装。
C实现Stack
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps)
{
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STPush(ST* ps, int x)
{
assert(ps);
//判断空间是否充足
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity * sizeof(int));
if (tmp == NULL)
{
perror("realloc file!");
return;
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top++] = x;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
void STPop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
STDataType STTop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
return ps->a[ps->top - 1];
}
int main()
{
ST s;
STInit(&s);
STPush(&s, 1);
STPush(&s, 2);
STPush(&s, 3);
STPush(&s, 4);
while (!STEmpty(&s))
{
printf("%d ", STTop(&s));
STPop(&s);
}
STDestroy(&s);
return 0;
}C++实现Stack
#include<iostream>
#include<assert.h>
using namespace std;
class Stack
{
typedef int STDataType;
public:
//成员函数
void Init(int n = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * n);
_top = 0;
_capacity = n;
}
void Push(STDataType x)
{
if (_top == _capacity)
{
int newcapacity = _capacity * 2;
STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
_a = tmp;
_capacity = newcapacity;
}
_a[_top++] = x;
}
void Pop()
{
assert(_top > 0);
_top--;
}
bool Empty()
{
return _top == 0;
}
int Top()
{
assert(_top > 0);
return _a[_top - 1];
}
void Destroy()
{
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
//成员变量
private:
STDataType* _a;
int _top;
int _capacity;
};
int main()
{
Stack s;
s.Init();
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
while (!s.Empty())
{
printf("%d ", s.Top());
s.Pop();
}
s.Destroy();
return 0;
}期待下次的《类和对象(中)》