类的定义:
class为定义类的关键字,stack为类的名字,{ };里面的内容为类的主体.(可以把class看作为结构体)
定义在类⾯的成员函数默认为inline。
为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加_ 或者 m 开头.
类的限定符:
public(公有)修饰的成员在类外可以直接被访问;protected和private(私有)修饰的成员在类外不能直接被访问,
访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到}即类结束。
class定义成员没有被访问限定符修饰时默认为private,struct默认为public。
⼀般成员变量都会被限制为private / protected,需要给别⼈使⽤的成员函数会放为public。
代码演示如下所示:(一般情况下成员函数在成员变量的上面)
class stack
{
public:
//成员函数
void init(int n = 4)
{
/*public(公有)修饰的成员在类外可以直接被访问;protected和private(私有)修饰的成员在类外不能直接被访问,
访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到}即类结束。
class定义成员没有被访问限定符修饰时默认为private,struct默认为public。
⼀般成员变量都会被限制为private / protected,需要给别⼈使⽤的成员函数会放为public。*/
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
void Push(int x)
{
// ...扩容
array[top++] = x;
}
int top1()
{
return array[top - 1];
}
private:
//成员变量
int* array;
size_t top;
size_t capacity;
};
int main()
{
stack st1;
st1.init();
st1.Push(1);
cout << st1.top1() << endl;
return 0;
}
类域:
类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员(成员变量或者成员函数)时,需要使⽤ :: 作 ⽤域操作符指明成员属于哪个类域。
class date
{
public:
void init(int year, int month, int day);//一般情况下函数在上,成员变量在下;
private:
// 为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如_ 或者 m开头
int _year;
int _month;//成员变量只是声明,没有开空间.
int _day;
};
在类外定义
void date :: init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
实例化:
类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只 是声明,没有分配空间,⽤类实例化出对象时,才会分配空间。
类可以实例化出n个对象,不同对象成员变量不一样,但成员函数是一样的.
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和d2
Date d1;
Date d2;
d1.Init(2024, 3, 31);
d1.Print();
d2.Init(2024, 7, 5);
d2.Print();
return 0;
}
this指针:
date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,当主函数中对象d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?此时便引入了this指针.
类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。⽐如date类的Init的真实原型为void Init(Date* const this, int year, int month, int day)
类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值,
this- >_year = year;
C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显 ⽰使⽤this指针。
class date
{
public:
// void Init(date* const this, int year, int month, int day)//不能再实参和形参写this
void Init(int year, int month, int day)//但是可以在函数体内显⽰使⽤this指针。
{
this->_year = year;
this->_month = month;
this->_day = day;
}
// void Print(Date* const this)//error
void Print()
{
cout << this->_year << "/" << this->_month << "/" << _day << endl;
}
private:
// 这里只是声明,没有开空间
int _year;
int _month;
int _day;
};
int main()
{
date d1;//一个类可以实例化多个对象.
date d2;//不同对象成员变量不一样,但成员函数是一样的.
d1.Init(&d1, 2024, 3, 31);this指针
d1.Init(2024, 5, 20);
d1.Print();
d2.Init(2024, 7, 10);
d2.Print();
return 0;
}
小练习:
程序正常运行
class A
{
public:
void Print()
{
cout<<this<<endl;
cout << "A::Print()" << endl;
}
private:
int _a;
};
//这是一个正常的类,不会编译出错.空指针不会出现编译错误只要没有解引用.
int main()
{
A* p = nullptr;
//调用函数需要传参: mov ecx p(对象的地址) ,p的值mov给ecx(存的是this指针,存的对象的地址),this指针是一个空指针,空指针不会报错,所以该程序正常运行.
p->Print();//转为汇编语言 call 地址(地址不在p对象里面)
return 0;
}
程序崩溃
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;//_a是通过this访问的,this是个空指针,空指针解引用会程序崩溃.
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}