类的引用
C语言是面向《过程》的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面《对象》的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
在C语言中,我们把一类的东西放在一个结构里面,用《struct》的结构来写,那么既然c++是C语言的衍生物,那么c++用什么来写,在c++中我们把《struct》换成《class》结构,用法和c语言中的差不多,但是又有非常大的区别。
在C语言中,我们把数据放在《struct》结构中,每一个人使用,都可以直接访问它,但是这样导致一个直接问题,如果我们不想让一些数据被访问,我们应该把这些数据保护起来,这样c++就给我们带来了许多的方便,下来我们就看一看在c++中的使用:
#include"iostream"(不知道为什么,我这里不能用<>,这个符号,所以用了双引号,但是记住一定是这个符号《 “<>” 》)
using namespace std;
class Date
{
public(共有):
protected(保护):
private(私有):
《这两个会在下面的类的访问及分装详细解说道》
};
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。
声明和定义可以放在一个《类体》里面,比如下面的图片:声明和定义也可以分开装:声明放在.h文件中,类的定义放在.cpp文件中
一般情况下,更期望采用第二种方式。
类的《访问限定符》和《封装》
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
上面的一小段代码涉及到了《public》和《private》。
【访问限定符说明】
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C)
那么问一个问题,c++中class 与 C语言中struct有什么区别呢???
解答:我们都只c++是兼容C语言的,所以在c++中也可以使用struct,且和class的用法一样,但是,在c++中struct的访问时private,在C语言中的访问是public。
《封装》:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
下面就是 类的作用域:
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用《 :: 》 作用域解析符
指明成员属于哪个类域。
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout<<_name<<" “_gender<<” "<<_age<<endl;
}
《类的实例化》
用类类型创建对象的过程,称为类的实例化
类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它, 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
那么如何计算 《类的大小》
这段代码就可把类里面成员的大小计算出来,但是及记得在调用的时候,void是无返回值,就是上面画红色的地方不要写return;
那么下面这段代码在类里面又是多大;
#include<iostream>
using namespace std;
class A1 {
public:
void f1()
{}
private:
int _a;
};
class A2 {
public:
void f2() // 类中仅有成员函数
{}
};
class A3 // 类中什么都没有---空类
{};
int main()
{
A1 d1;
cout<<sizeof(d1)<<endl;
A2 d2;
cout<<sizeof(d2)<<endl;
A3 d3;
cout<<sizeof(d3)<<endl;
//d1.Print();
return 0;
}
下面就来说下一下答案
答案是4,1,1,为什么呢?有的同学肯定有这样的疑问;那是因为一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
结构体内存对齐规则
- 第一个成员在与结构体偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8,gcc中的对齐数为4 - 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么要内存对齐?
答:当进行访问的时候,就可以直接读取,但是如果不内存对齐的话,直接访问的话,就比如说一个char一个double,不对齐的话,有char开始访问8个字节(为什么访问8个字节,上面内存对齐说过了),已经访问double一次了,到访问double的时候,又一次访问,总共访问了两次,浪费时间。
总结:最重要的是 内存对齐是 <<浪费空间,提高效率>>
下面就到了重要的一个问题**《this》指针**
this指针的由来:我们先看下面一段代码:
#include
using namespace std;
class Date
{
public :
void Display ()
{
cout <<_year<< “-” <<_month << “-”<< _day <<endl;
}
void SetDate(int year , int month , int day)
{
_year = year;
_month = month;
_day = day;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
int main()
{
Date d1, d2;
d1.SetDate(2018,5,1);
d2.SetDate(2018,7,1);
d1.Display();
d2.Display();
return 0;
}
对于上述类,有这样的一个问题:
Date类中有SetDate与Display两个成员函数,函数体中没有关于不同对象的区分,那当s1调用SetDate函数时,该函数是如何知道应该设置s1对象,而不是设置s2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
这幅图片就可以明确表明this指针的《存在》和《隐含》,但是这个不能传值,会直接报错;
问题一:
this指针存在哪里? 它存在栈上面:
问题二:
this指针可以为空?
给一段代码:
#include
using namespace std;
class Date
{
public:
void PrintA()
{
cout<<_a<<endl;
}
void Show()
{
cout<<“Show()”<<endl;
}
private:
int _a;
};
int main()
{
Date* p = NULL;
//1.p->PrintA();
//2.p->Show();
}
当运行上面一段程序时,出现怎么样的情况,《崩溃》还是《运行正常》?
当打开1是程序会出现下面情况
当关闭1,打开2是程序又会是下面情况
当然,如果两个都打开的话程序肯定是崩溃的,那么为什么会出现这样的情况,
当是第一种情况的时候,我们知道,在类里面有一个隐含的指针《this》指针,如果我们定义一个空指针,去节引用,就好想是this->_a还要去节引用它的地址,明知知道找不到,还要找,当然就是崩溃了,那第二种情况,我们虽然是空指针,但是调用他这个函数,就相当于,this->去访问他自己,没有使用这个空指针,所以可以正常使用。
它是一个空指针,但是它没有节引用对象,cout << this << endl;
下面是因为节引用 cout << this->_a << endl: 空->节引用: