目录
类的引入
C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如以下代码,就可以编译通过:
main函数中的st,就称为对象,以上结构体的定义,在C++中一般使用class代替。
类的定义
类定义的格式如下:
class className{
//类体,由成员函数和成员变量组成
};
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。
将以上结构体的代码做以下更改,依然可以通过编译:
![](https://i-blog.csdnimg.cn/blog_migrate/3efd2c7ec3d1a0a0fddd02727654295b.png)
把struct更改成了class,代码依然没有问题,st还是初始化后的对象。
类的访问限定以及封装
1.访问限定符的说明
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
在以上两段代码中,把struct改成class后,我们会发现在代码的第二行,多了一个访问限定符:public。它们两个出现了不同,那么由此引出以下问题:
(面试题)C++中struct和class的区别是什么?
答:C++需要兼容C语言,所以C++中struct可以当作结构体去使用。另外,C++中的struct还可以用来定义类。和class定义类是一样的,区别是struct定义出来的类中的成员默认访问限定符是public,而class定义出来的类中的成员默认访问限定符是private。
由此就可以理解以上class定义出来的类为什么在第二行加public了。
2.封装
面向对象的三大特征:
封装、继承、多态。
C++的封装方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部外部的用户使用。
例如以下日期类,用private修饰成员变量,将成员变量封装了起来,对外提供用public修饰的成员函数,来进行对成员变量的访问。
![](https://i-blog.csdnimg.cn/blog_migrate/c7696e1de6197b994db3712bf45a1a1d.png)
类对象的大小
还是使用以上的日期类,我们来计算类对象的大小:
![](https://i-blog.csdnimg.cn/blog_migrate/463b17de5d904837868d91d6a21256cd.png)
此时类对象的大小居然只有12个字节,在类对象中,三个整型变量的大小都已经是12个字节了,从以上结果来看,代码并没有存储在类对象中 ,而是在其他的位置。如下图:
类对象所使用的成员方法只有一份,存储在代码区。
结论:一个类的大小,实际就是该类中
”
成员变量
”
之和,当然也要进行内存对齐,注意空类的大小,空类比
较特殊,编译器给了空类一个字节来唯一标识这个类。
this指针
分析以下日期类的代码:
![](https://i-blog.csdnimg.cn/blog_migrate/9e09358d1edaa855da7f0425d512848c.png)
以上代码对两个不同的对象都进行了初始化,且都成功了。根据上面的分析,成员函数只有一份,而且函数体中没有关于不同对象的区分,是怎么做到用d1调用函数就设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参 数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
以上代码编译后,会添加this指针,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/7e80b7cdb9c2610365525c114f48ea11.png)
this指针的特性:
1. this指针的类型:类类型* const
2. 只能在“成员函数”的内部使用
3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传给this形参。所以对象中不存储this指针。
4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
面试题
// 1.下面程序能编译通过吗?
// 2.下面程序会崩溃吗?在哪里崩溃
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
void Show()
{
cout<<"Show()"<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
p->Show();
}
1.答:上面的程序没有语法错误,可以通过编译。
2.答:会崩溃,在语句: p->PrintA() 处崩溃,此时相当与对p空指针进行了访问,引发崩溃。而单独执行:p->Show() 语句并不会崩溃。
单独执行p->PrintA():
![](https://i-blog.csdnimg.cn/blog_migrate/8aa7c6788af86a9e2d20966de25ac67a.png)
单独执行p->Show():