目录
类的引入
类的定义
类的访问限定符及封装
访问限定符
封装
类的作用域
类的实例化
this指针
this指针的特性
两个经典问题
类的引入
在C语言的结构体中,只能定义变量。C++在此基础上进行了升级,在C++中,结构体内既可以定义变量,也可以定义函数。类是定义同一类所有对象的变量和方法的蓝图或原型。
类的定义
类的定义格式:
class 类名
{
/ /类体:由成员函数和成员变量组成
/ / ……
}; / /分号不能少
class为定义类的关键字。
类体中的内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或成员函数。
如果成员函数在类中声明和定义,那么编译器可能会把它当做内联函数处理。、
类的访问限定符及封装
访问限定符
用类将对象的属性和方法结合在一块,使对象跟完善,通过访问权限选择性的将其接口提供给外部用户使用。
类的三个访问限定符:
访问限定符的说明:
>> public修饰的成员在类外可以直接进行访问。
>> protected 和 private 修饰的成员在类外不能直接被访问。
>> 访问限定符的作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
>> 如果后面没有访问限定符,作用域就到 } 即类结束。
>> class的默认访问权限为private,struct的默认访问权限为public。这是class和struct的一个区别。
封装
面向对象的三大特性:封装、继承、多态。这里只对封装进行介绍。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义类的成员时,需要使用::域作用限定符,指明所定义的成员属于哪个类域。
class A
{
public:
int Add(int x, int y);
private:
int _a;
int _b;
};
int A::Add(int x, int y)
{
return x + y;
}
int main()
{
A a;
cout << a.Add(1, 2) << endl;
return 0;
}
类的实例化
用类类型创建对象的过程叫做类的实例化。
类是对对象进行描述的,是模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。可以把类理解为一张图纸,并没有真正的建造出房子来。
一个类可以实例化出多个对象,实例化的对象占用实际的物理空间,存储类的成员变量。
this指针
下面用一段代码引入:
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;
d1.Init(2024, 4, 1);
d1.Print();
Date d2;
d2.Init(2024, 4, 2);
d2.Print();
return 0;
}
Date类中的两个成员函数Init和Print,它们的函数体中并没有关于不同对象的区分,所以当d1在调用Init函数的时候,它是怎么知道应该去设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针来解决这个问题。
C++编译器给每个【非静态成员函数】增加了隐藏的指针参数this,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中,所有成员变量的操作都是通过该指针去访问,只不过这些操作对用户来说是透明的,即用户不需要来传递,编译器会自动完成。
this指针的特性
下面将借助这段代码引出指针的特性:
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
this = NULL;//验证this指针的指向是否可以改变
}
void Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
上面代码中,this = NULL; 这句代码是在验证this指针的指向是否可以改变,编译结果是:
所以可以得出this指针的第一个特性:
>> this指针的指向不可改变,其类型为 类类型 * const。
>> this指针只能在成员函数内部使用。
>> this指针本质上时成员函数的形参,当对象调用成员函数时,将对象的地址作为实参传给this指针。
>> this指针是成员函数隐含的第一个指针形参,一般由编译器通过ecx寄存器自动传递,不需要用户传递。
两个经典问题
1、this指针存在哪?
2、this指针可以为空吗?
this指针是成员函数隐含的一个形参,所以this指针存储在栈中。可以通过一下代码证明:
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
Date* const& rthis = this;
cout << &rthis;//通过this的引用来打印this的地址。
//cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Print();
return 0;
}
打开监视窗口,可以看到:
this的地址在esp和ebp之间,说明this存储在栈中。
第二个问题,这里暂时不给结论,先看代码:
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;
d1.Init(2024, 4, 1);
Date* p = &d1;
p = nullptr;
p->Print();//报错
return 0;
}
this指针为空,并且在Print函数中利用this指针去访问成员变量,所以会报错。
再看另一种情况:
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()//在函数体中并没有通过this指着去访问成员变量
{
cout << "welcom to C++" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2024, 4, 1);
Date* p = &d1;
p = nullptr;
p->Print();//正常运行
return 0;
}
所以问题的答案为:
this指针可以为空,但是,当this指着为空时,不可以用它去访问成员变量,否则会报错。
完