目录
1.面向过程和面向对象
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用解决问题。
C++是基于面向对象的,关注的是对象,将一件事分成不同的对象,靠对象的交互完成任务。
我们可以简单理解为这些对象,C++ 习惯存放在 类中 ,也就是类域中。
2. 类的定义
2.1 struct 定义类
struct structname
{
// 类体 ,包括成员变量和成员函数
}; //不要忘记分号
struct 为C++ 定义类的关键字 ,structname 是我们为这个类 起的名字。
由于C++ 是支持C语言的,因此 ,在C++中 ,我们可以使用struct 来定义结构体,并且正常使用。在C语言中 我们定义的结构体,其内容只有成员变量,但是在C++中,我们可以在类中定义成员函数,这是C语言办不到的。
2.2 class定义类
class classname
{
// 类体 ,包括成员变量和成员函数
}; //不要忘记分号
C++中更推荐使用 class 来定义类,class为定义类的关键字,classname为类名,{} 中为类的主体。同样,class定义的类,包括成员变量(也可以称为类的属性)和成员函数(也可以称类的方法)
那么class 和 struct 同样都可以用来定义类 ,那么它们有没有什么不同?
3.类的访问限定符及封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅公开接口来和对象进行交互。封装的本质更像是管理
C++实现封装的方式: 用类将对象的属性和方法结合在一起,让对象更加完善,通过访问权限选择性的将接口提供给外部的用户使用。
简单的来说,给我们定义的类 ,上了很多把锁,只有拿到对应的钥匙,才能访问相应的内容,
或者,在我们定义类的时候,提前把我们希望提供给外部的接口上的锁打开。
访问限定符:
1. public (公有)
2.protected (保护)
3. private (私有)
public 修饰的类的成员 可以在类外直接被访问。
protected 和 private 修饰的成员在类外 不可以直接被访问。
访问权限作用域从该访问限定符出现的位置 到下一个访问限定符出现为止。
class 的默认访问权限为 private ,struct 默认访问权限为 public (因为它需要兼容C)
我们需要注意的是 ,访问限定符只有在编译的时候有用,当数据映射到内存时,没有任何访问限定符上的区别。
class classname
{
public:
void test1()
{
cout << "test1" << endl;
}
private:
int a = 10;
int b = 20;
};
例如我们现在定义的类,它的test1函数,可以在类外面被直接调用,但是 a , b 就不可以直接被调用。
4. 类的作用域
类定义了一个新的作用域,类中的成员都在类的作用域中。如果在类体外定义成员,需要用到作用域解析符 :: (两个英文的冒号),用来指明成员属于哪个类域。
这里顺带说明一下类的两种定义方式:
1.声明和定义全部放在类中,需要注意的是,成员函数在类中定义,编译器可能会把它当做内联函数来处理。不过这取决于具体的情况。
class classname
{
public:
void test1() // 声明
{
cout << "test1" << endl; / 定义
}
private:
int a = 10;
int b = 20;
};
2. 声明放在.h文件中 , 类的定义放在.cpp 文件中。
.h
class classname
{
public:
void test1() // 声明
private:
int a = 10;
int b = 20;
};
.cpp
#include"test.h"
void classname :: test1()
{
// 具体实现
}
这里我们就用到了 作用域解析符 ::
我们定义类时,更推荐第二种。
5. 类的实例化
用类类型创建对的过程就叫类的实例化。
类本身更像一个模型,它限定了类中有哪些成员,定义出一个类,并没有分配实际的内存空间来存储它。
一个类可以实例化出多个对象。它实例化的对象,占用实际的物理空间,存储类成员变量。
6.类对象模型
我们知道类中,即可以有成员变量,有存在成员函数,那么一个对象中到底包含了什么,如何计算类的大小?
直接说结论
类中只保存成员变量,成员函数存放在公共代码段。
为什么成员函数和成员变量不一样?如果每个对象都保存一份代码,相同的代码保存多次,浪费空间。每个成员变量是不同的,所以它们保存在对象中。
那么一个类的大小,就是该中成员变量和,和C语言中的结构体内存大小的计算规则相同,需要考虑内存对齐。下面是具体的结构体内存大小计算的博客链接。
(35条消息) 结构体内存大小计算,位段分析_杨斯文。的博客-CSDN博客
但是C++中,我们需要注意空类的大小,空类比较特殊,即类中没有成员变量。空类的大小不是0,而是一个字节,因为编译器给了空类一个字节来唯一标识这个类。
7. this指针
需要我们用一个例子来说明
class Date
{
public:
void display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = _month;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2; // 创建两个类对象
d1.SetDate(2019, 9, 10);
d2.SetDate(2022, 9, 18);
d1.display();
d2.display();
}
我们创建两个类对象,在我们给对象赋值时,调用了处于公共代码段的成员函数。那么问题来了,直接调用相同的成员函数,那么函数是给d1还是给d2运行,还是说成员函数有方法识别这两个不同的对象。我们来运行一下这个代码。
我们可以看到,成员函数正确的操作了两个不同的类对象。包括打印函数也是。
但是这不符合正常的逻辑。按道理,这个函数并不能区分出两个不同的类对象。
这里就不得不提出 this指针了。
C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所以成员变量的操作,都是通过该指针去访问。
只不过这个操作,对用户来说是透明的,不需要用户来实现,编译器自动完成。
7.1 this 指针的特性
1. this 指针的类型 : 类类型 * const ( const 的作用是 ,保证 this 这个指针不可以改变 )
2. 只能在成员函数内使用。
3.this 指针本质是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this 形参。所以对象中是不存储 this 指针 。
4. this指针是成员函数第一个隐含的指针形参,一般情况有编译器通过ecx 寄存器自动传递,不需要用户传递。
那么上述代码的运行结果就可以解释了
除此以外this 指针还有几个我们需要注意的点。
this 指针的存储位置 , 一般情况是在栈(形参),有些编译器会放在寄存器中。
this 可以为空吗?
class Date
{
public:
void display()
{
cout << _year << "-" << _month << "-" << _day <<"test"<< endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = _month;
}
void show()
{
cout << "shou" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date* p = nullptr;
p->show();
}
此时p为空 ,我们运行程序。
程序正常运行。
int main()
{
Date* p = nullptr;
p->display();
}
当我们运行打印函数时,会发现
函数没有崩,但是也并没打印出我们相要的。
我们开辟一个空的类的对象时,传给this的是空,也就是实参是空 ,此时this 作为形参接收了一个空,成为空指针。直到这一步,都是没有错误的。
这也是为什么,我们可以正常使用 show 函数,
但是当我们调用的函数会对this 这个空指针进行解引用时 ,属于对空指针进行操作。这是不对的。所以打印函数没有运行。按道理程序是应该报错的。
所以this 是空指针是没有问题的 ,但是我们在使用时,需要注意,避免使用野指针。
本篇博客到此结束,谢谢观看。