目录
[1. 什么是类](#1. 什么是类)
[2. 如何定义出一个类](#2. 如何定义出一个类)
[3. 类的访问限定符](#3. 类的访问限定符)
[4. 类的作用域](#4. 类的作用域)
[5. 类的实例化](#5. 类的实例化)
[6. 类的大小](#6. 类的大小)
[7. this指针](#7. this指针)
[2. this指针的特性](#2. this指针的特性)
[8. 面试题](#8. 面试题)
1. 什么是类
在C语言中,不同类型的数据集合体是结构体。为了方便管理结构体,我们经常会为此而编写出各种针对于这个结构体的函数(如:在C语言中为了方便管理顺序表,我们经常为此写出许多针对于该顺序表的增删查改的函数)。为了方便管理数据集合体,以及针对于该数据集合体的函数。我们将它们都打包起来,将函数作为成员一起纳入了该数据集合体中。此外,这也方便了我们对变量和函数进行命名。
2. 如何定义出一个类
cpp
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class 为 定义类的 关键字, ClassName 为类的名字, {} 中为类的主体,注意 类定义结束时后面 分
号不能省略 。
类体中内容称为 类的成员: 类中的 变量 称为 类的属性 或 成员变量 ; 类中的 函数 称为 类的方法 或者
成员函数 。 值得注意的是, 类的定义有两种。第一种是类中的成员函数在类当中定义;第二种是类中的成员函数在类当中声明,在其他文件中定义。
如:
在实际当中,我们定义一个类经常都是采用声明定义分离的方法。当然了,你也可以部分简单的函数在类中定义,其余的函数在其他文件定义。
3. 类的访问限定符
C++ 实现封装的方式: 用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选
择性的将其接口提供给外部的用户使用。
【访问限定符说明】
- public 修饰的成员在类外可以直接被访问
- protected 和 private 修饰的成员在类外不能直接被访问 ( 此处 protected 和 private 是类似的 )
- 访问权限 作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class 的默认访问权限为 private , struct 为 public( 因为 struct 要兼容 C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
4. 类的作用域
类定义了一个新的作用域 ,类的所有成员都在类的作用域中 。 在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域。
cpp
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
5. 类的实例化
用类这个类型创建对象的过程,称为类的实例化
cpp
class Person
{
private:
int _age;
char _name[20];
public:
print();
};
int main()
{
Person a;
return 0;
}
以上就称为类的实例化。
值得注意的是类是没有内存空间的,只有实例化后的类才有内存空间。类就好比一个房子的建造图纸,实例化后的类就是建好后的房子。还没开始建造的房子当然无法使用。因此再未实例化之前你是无法使用类的。
cpp
int main()
{
Person._age = 100; // 编译失败:error C2059: 语法错误:"."
return 0;
}
6. 类的大小
类的内存依旧是遵循内存对齐的机制,值得注意的是一个实例化后的类的内存是与其成员函数没有关系的(它的成员函数储存在代码段中)。因为如果每个对象中都会保存一份代码,而所有的类的成员函数都是一模一样的,相同代码保存多次,浪费空间。
7. this指针
1.this指针的引出
我们先来定义一个日期类 Date
cpp
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;
d1.Init(2022,1,11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
对于上述类,有这样的一个问题:
Date 类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当 d1 调用 Init 函
数时,该函数是如何知道应该设置 d1 对象,而不是设置 d2 对象呢?
C++ 中通过引入 this 指针解决该问题,即: C++ 编译器给每个 " 非静态的成员函数 " 增加了一个隐藏
的指针参数,让该指针指向当前对象 ( 函数运行时调用该函数的对象 ) ,在函数体中所有 " 成员变量 "
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成 。
2. this****指针的特性
- this 指针的类型:类类型 * const ,即成员函数中,不能给 this 指针赋值。
- 只能在 " 成员函数 " 的内部使用
- this 指针本质上是 " 成员函数 " 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给
this 形参。所以 对象中不存储 this 指针 。 - this 指针是 " 成员函数 " 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传
递,不需要用户传递
8. 面试题
- this 指针存在哪里?
- this 指针可以为空吗?
cpp
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}