类的本质是封装 ,相比c语言,c语言的数据和方法都是分离的,c++把数据和方法都放到了类里面
类的定义格式:
class Stack//定义一个栈
{
private:
void Init(int capacity=4)
{
_array=(int*)malloc(sizeof(int)*capacity);
assert(_array);
_capacity=capacity;
_top=0;
}
public:
int*_array;
size_t _capacity;
size_t _top;
} class为定义类的关键字,Stack为类的名字,{}中为类的主体
类中的内容:类的成员
类中变量:成员变量,一般为了却分成员变量,会在变量名前加一个特殊标识符
类中可以定义函数,称为成员函数
定义在类里面的成员函数默认为内敛函数
内联函数的概念
内联函数(Inline Function)是C++中一种优化函数调用的机制,通过将函数体直接插入调用处来避免函数调用的开销(如压栈、跳转、返回等)。适用于短小且频繁调用的函数。
内联函数的定义
在函数声明或定义前添加 inline 关键字即可将其标记为内联函数:
inline int add(int a, int b) {
return a + b;
}编译器会根据实际情况决定是否真正内联(如递归函数、复杂函数可能被忽略)。
内联函数的优势
内联函数的限制
inline 仅是建议,编译器可能拒绝复杂函数的内联请求。内联函数与宏的区别
#define SQUARE(x) x*x 调用 SQUARE(++x) 会出错)。内联函数的使用场景
示例代码
#include <iostream>
using namespace std;
inline int max(int x, int y) {
return (x > y) ? x : y;
}
int main() {
cout << max(10, 20); // 可能被替换为 cout << (10 > 20 ? 10 : 20);
return 0;
}注意事项
inline。public,后面的内容为共有
private\ protected,后面内容为私有
class Stack
{
piblic:
void Init(int n=4)//给栈初始化
{
....
}
void push(int x)//入栈
{
...
}
private:
int *array;
size_t capacity;
size_t top;
}一般成员函数是公有的,成员变量是私有的。
访问权限的范围,比如上面public,从“:”开始,一直到private ,也就是从自身到下一个访问限定符,如果只有一个访问限定符,那么就是直接到“}”结束。
在class中,如果没给出访问限定符,那么默认是私有
在类中,不管是私有还是公有,都是能访问的
在c++中,struct也可用来定义类,当struct中没有给出访问限定符时,默认是公有
c++struct的用法兼容c

域的作用是影响编译器的查找,做到名字的隔离
会影响到编译器的查找,如果不指定类域,编译器在编译时将不会访问类域
类是没有被分配空间的,只有类实例化出的对象才会被分配空间
类就像一个房子的设计图,告诉了我们房子的样式,但不能住人,换类来说就是不能存数据,只有类实例化出的对象才能存数据
一个类可以实例化多个对象
class Data
{
private://这是声明
int _year;
int _month;
int _day;
};
int main()
{
//这是类定义一个对象,也叫类实例化出对象
Data d1;
Data d2;
}
//类与对象的关系:1对多,一个类可以实例化出多个对象。对象大小
类实例化出的对象也是有大小的。
类实例化出的对象只会在对象中存储类中的成员变量,不会存储成员函数。因为存储成员函数是没必要的,我们每次调用的成员函数都是同一个,他们唯一的区别就是在调用函数时传入的数据不同。如果我们非要在对象中存储成员函数,那么存储的是成员函数的指针,我们每实例化一个对象,就得存储一次指针,存储100个,就得存储100个指针,但是这些个空间是完全没必要的,是一种空间的浪费。

计算对象的大小时,也存在内存对齐(与结构体一样):
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
计算A实例化对象的大小A中,存在两个成员变量 ch 与i
_ch是char类型,又是第一个元素,那么它放在偏移量为0的地址出,占1字节

class B
{
public:
void Print()
{
//...
}
};
计算B实例化对象的大小因为实例化对象中,只会存储成员变量,该代码中没有成员变量,所以实例化出的对象大小为1字节,着一个字节是用来占位的,表示对象存在过,无其他意义。
class C
{};
计算C实例化对象的大小这段代码与上述的B一样。
在d1 、d2调用方法时,编译器是怎么知道方法应该访问d1还是d2?
编译器编译后,类的成员函数都会默认在形参的第一位置,增加一个当前类类型的指针叫做this。
类的成员函数访问成员变量,本质是通过this指针来访问的。
c++规定,不能在形参实参的位置显示写this指针,但可以在函数体内显示的使用this指针。
class Data
{
public:
void Init(int year,int month,int day)//Init(Data*this.....)
{
_year = year;
_month = month;
_day = day;
}
void Print()//Print(Data*this)
{
//cout << this->_year << '/' <<this-> _month << '/' << this->_day << endl;
cout << _year << '/' << _month << '/' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;
Data d2;
//d1.Init(&d1,2024,2,3);
//d2.Init(&d2,2024,3,1);
d1.Init(2024,2,3);
d2.Init(2024,3,1);
//d1.Print(&d1)
//d2.Print(&d2)
d1.Print();
d2.Print();
return 0;
}如果我们要让this指针指向对象的值无法被修改,我们可以用const来修饰this。
class Test
{
public:
Test()
{
a = 10;
}
int get_val()const//
{
this->a = 20;//这里编译器会报错,因为this指针被const修饰,无法通过this指针
return a;
}
private:
int a;
};
int main()
{
Test t1;
int ret = t1.get_val();
cout << ret << endl;
return 0;
}
面向对象三大特性:封装、继承、多态
c++中数据与方法都放在了类里面,通过访问限定符进行了限制,不能再随意的通过对象对数据进行修改。避免出现乱访问修改的问题。
c++有一些相对方便的语法,比如缺省参数。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
// 满了, 扩容
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity *sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
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 STSize(ST* ps)
{
assert(ps);
return ps->top;
}
int main()
{
ST s;
STInit(&s);
STPush(&s, 1);
STPush(&s, 2);
STPush(&s, 3);
STPush(&s, 4);
while (!STEmpty(&s))
{
printf("%d\n", STTop(&s));
STPop(&s);
}
STDestroy(&s);
return 0;
}#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
// 成员函数
void Init(int n = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * n);
if (nullptr == _a)
{
perror("malloc申请空间失败");
return;
}
_capacity = n;
_top = 0;
}
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;
size_t _capacity;
size_t _top;
};
int main()
{
Stack s;
s.Init();
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
while (!s.Empty())
{
printf("%d\n", s.Top());
s.Pop();
}
s.Destroy();
return 0;
}