1类的定义
cpp
class stack
{
public:
private:
int* _array;
int _top;
int _capacity;
};
cpp
class Date
{
public:
void Init(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2010, 12, 30);
return 0;
}
cpp
typedef struct ListNodeC
{
int val;
struct ListNodeC* next;
}LNode;
struct ListNodeC
{
ListNodeC* next;
int val;
}LTNode;
struct ListNodecpp
{
//默认是public
void Init(int x)
{
val = x;
next = nullptr;
}
ListNodecpp* next;
int val;
};
1类的定义格式
class定义类的关键字 stack类的名字 {}中为类的主体 类后面有一个分号不可以省略
类中的内容叫做类的成员
类中的变量叫做类的属性或者类的成员变量
类中的函数叫做类的方法或者类的成员函数
区分成员变量我们通常在变量前面➕ (eg::_array)
C++兼容了C中struct的用法,同时strucrt也可以定义类。struct中也可以定义函数。
定义在类里面的函数默认为inline(内联)
2访问限定符
1private protected public
C++实现封装的一种方式 用类将对象的属性和方法结合在一起,对象更加完善,通过访问权限选择性的将其接口给用户使用。
public修饰的成员在类外部可以直接访问,private和protected修饰的成员在类外部不能直接访问到,private protected目前看是一样的,学习继承才会体现出区别。
2访问限定符的作用域
从该限定符出现位置开始到下一个访问限定符出现位置为止,如果后面没有访问限定符,那么到作用域}即类结束
class中成员默认为private,struct中默认为public
一般成员变量修饰为private,需要给别人使用的成员函数放为public
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3类域
类定义了一个新的作用域,类的所有成员都在这个作用域内,在类外面定义成员,需要使用::(作用域操作符)指明成员属于哪个类域。
类域影响编译查找原则
cpp
class stack
{
public:
void Init(int n = 4);//声明
private:
int* _array;
int _top;
int _capacity;
};
void stack::Init(int n)//定义
{
if (_top == _capacity)
{
_array=(int*)malloc(sizeof(int) * n);
if (_array == nullptr)
{
perror("malloc fails");
return;
}
_capacity = n;
_top = 0;
}
}
int main()
{
stack st;
st.Init();
return 0;
}
如果上面这个程序Init不指定类域,编译器就会把Init认为是全局函数,编译时就会找不到_array,_top,_capacity这些成员的声明或者定义,就会报错,指定类域stack,就知道Init是成员函数,在当前域找不到_array这些成员,就会到类域中去找。
2类实例化
概念
用类类型在物理内存中创建对象的过程,叫做类的实例化出对象。
类是对象的一种抽象描述,是模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有开空间,用类实例化出对象才会分配空间。
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理内存,存储类成员变量。
对象的大小
函数指针
函数指针是一个地址,调用函数就是调用函数编译产生的汇编指令[call]指令,其实函数在编译时就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址。
cpp
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;// p就是类的地址mov ecx p
p->Print();//call 地址
return 0;
}
成员变量
实例化对象也要符合内存对齐原则
cpp
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
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;
}
内存对齐规则
1第一个成员在 与结构体偏移量为0的地址处
2其他成员要对齐到对齐数(编译器默认的一个对齐数 与 该成员大小的较小值)的整数倍地址处
vs默认对齐数为8
结构体的总大小:最大对齐数(所有变量类型最大值与默认对齐数取小)的整数倍
3嵌套结构体
嵌套结构体对齐到自己最大对齐数的整数倍
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)整数倍
3类的默认this指针
引入
当实例化出两个对象d1,d2,当d1调用Init和Print两个函数,该函数是怎么知道访问的是d1对象还是d2对象,c++给了一个隐含的this指针来解决这个问题
编译器编译后,类的成员函数会在形参的第一个位置,增加一个当前类 类型的指针(this指针)
比如 Init的原型是Init(Date* const this,int year,int month,int day)
类的成员函数访问成员变量,本质都是通过this指针访问的比如this->_year=year;
C++规定 this指针在函数的实参和形参部分都不可以显示写(编译器会处理),但是在函数体内可以显示使用this指针
cpp
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;
}
void Print()
{
cout<<_year<<"/"<<_month<<"/"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
//int main()
//{
// Data d1;
// Data d2;
// d1.Init(2004, 07, 16);
// d1.Print();
//
// d2.Init(2005, 9, 16);
// d2.Print();
// return 0;
//}
4C语言和C++写栈的区别
cpp
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps)
{
//指向一个存在的表
assert(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, 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);
if (tmp == NULL)
{
perror("realloc fails");
exit(1);
}
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));
//assert(ps->top > 0);
--ps->top;
}
//返回栈顶元素
STDataType STTop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
//assert(ps->top > 0);
return ps->a[ps->top-1];
}
//返回栈元素数目个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
int main()
{
ST st;
STInit(&st);
STPush(&st, 1);
STPush(&st, 2);
STPush(&st, 3);
STPush(&st, 4);
//取出栈里面的每一个元素
while (!STEmpty(&st))
{
cout << STTop(&st) << endl;
STPop(&st);
}
STDestroy(&st);
return 0;
}
class Stack
{
public:
void Init(int n = 4)
{
//指向一个存在的表
_a =(int*)malloc(sizeof(int) * n);
_top = _capacity = 0;
}
void Destroy()
{
//指向一个存在的表
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
void STPush(int x)
{
//指向一个存在的表
//扩容
if (_top == _capacity)
{
int newcapacity = _capacity * 2;
STDataType* tmp = (STDataType*)realloc(_a, newcapacity);
if (tmp == NULL)
{
perror("realloc fails");
exit(1);
}
_a = tmp;
_capacity = newcapacity;
}
_a[_top++] = x;
}
//判空
bool STEmpty()
{
////指向一个存在的表
return _top == 0;
}
//删除栈顶
void STPop()
{
//指向一个存在的表
assert(_top > 0);
--_top;
}
//返回栈顶元素
STDataType STTop()
{
assert(_top > 0);
//assert(ps->top > 0);
return _a[_top - 1];
}
//返回栈元素数目个数
int STSize()
{
return _top;
}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack st;
st.Init();
st.STPush(1);
st.STPush(2);
st.STPush(3);
st.STPush(4);
while (!st.STEmpty())
{
cout << st.STTop() << endl;
st.STPop();
}
st.Destroy();
return 0;
}