目录
一.类的定义
1.1类定义格式
#include<iostream>
using namespace std;
class Stack
{
//类的方法或成员函数
void Init(int n = 4)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
//类的属性或成员变量
int* array;
int capacity;
int top;
};
#include<iostream>
using namespace std;
//在C++中兼容C的结构体用法
typedef struct ListNodeC
{
struct ListNodeC* next;
int val;
}LTNode;
//C++中也可以是类,不再需要typedef,ListNodeCPP就可以直接表示类型
struct ListNodeCPP
{
void Init(int x)
{
next = nullptr;
val = x;
}
ListNodeCPP* next;
int val;
};
1.2访问限定符
这里需要注意的一点是,struct与class的区别,没有加限定符的时候struct是public,class是private。
1.3类域
(1)类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使⽤ :: 作用域操作符指明成员属于哪个类域。
(2)类域影响的是编译的查找规则,下面程序中Init如果不指定类域Stack,那么编译器就把Init当成全局函数,那么编译时,找不到array等成员的声明/定义在哪里,就会报错。指定类域Stack,就是知道Init是成员函数,当前域找不到的array等成员,就会到类域中去查找。
#include<iostream>
using namespace std;
class Stack
{
public:
void Init(int n = 4);
private:
int* array;
int capacity;
int top;
};
//函数声明与定义分离,定义时需要指定类域
void Stack::Init(int n)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
二.实例化
2.1实例化概念
#include <iostream>
using namespace std;
class Data
{
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()
{
//这里实例化出对象d1和d2
Data d1;
d1.Init(1, 1, 1);
Data d2;
d2.Init(2, 2, 2);
d1.Print();
d2.Print();
return 0;
}
这里需要记住一个点,类里不开空间,主函数里实例化出对象了再开空间。
2.2对象大小
在说对象大小之前,我们需要知道类里的对象包含什么,我们知道,类实例化出来的每个对象都有独立的数据空间,所以对象里肯定包含成员变量。那包不包含成员函数呢?
然后就是如何计算对象的大小了,这里依然符合一起我们计算的结构体的内存对齐的规则。
三.this指针
//void Init(Data* const this, int year, int month, int day)
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Init(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
但是需要注意的是,我们不可以把Init函数写成:void Init(Date* const this, int year, int month, int day)。同时this指针是常量指针,不能用nullptr。
这里分享一个题目:
#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;
}
这段代码会编译报错吗?答案是这段代码会正常运行。
虽然p是空指针并且有p->Print()。很多人就会以为有->就会解引用,但是实际上不是的,我们可以转到汇编代码看一下:
因为p本身就是地址,不需要有lea取地址的过程。所以这句代码有两个过程,一个是mov一个是call。mov是把p的地址传递给rcx,call是调用Print函数(后面就是它的地址)。Print函数的地址是在编译时确定的,不会到p里去找。所以这里没有解引用的过程,也就不会报错。
当然如果这样就不行了:
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
到这里本篇就结束了,感谢大家的观看,如有错误还请多多指出。