前言
前面讲到了C++的入门需要学习的知识,是为了后面更好的学习。学习是不断深入的,内容是不断复杂的。笃定信心。
一、面向对象编程(OOP)和面向过程编程(POP)的认识
面向过程编程(Procedural Programming,简称POP)
POP特性
- 程序的核心是函数,这些函数是一系列预定义操作的集合,旨在执行特定任务。
- 这种方法让程序员可以重用代码,提高效率,并且使代码更易于跟踪和维护。
- 通过将复杂问题拆解为更小、更具体的任务,面向过程编程使解决问题变得更加直接.
面向对象编程(Object Oriented Programming,简称OOP)
OOP特性
- 封装:是将对象的属性和方法结合在一起,并尽可能隐藏对象的内部细节,只暴露必要的接口供外部使用。
- 继承:允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码的重用和层次化组织。
- 多态:允许使用相同的接口来处理不同类型的对象,具有不同的实现,增加了代码的灵活性和可扩展性.
二、类
类的定义:类是用户自定义的数据类型,它允许将数据(成员变量)和操作数据的函数(成员函数)封装在一起。
类的定义
class ClassName { public: // 公共成员声明 private: // 私有成员声明 protected: // 受保护成员声明 };
访问限定修饰符
- public(公有):公有成员可以在类的内部、派生类和类的外部访问。它们构成了类的公共接口,通常用于定义可以被外部直接访问和操作的方法和属性。
- protected(受保护):受保护的成员只能在类的内部和派生类中访问,而不能在类的外部访问。它们用于实现基类和派生类之间的共享实现细节。
- private(私有):私有成员只能在类的内部访问,外部无法直接访问。私有成员用于隐藏类的内部实现细节,防止外部代码直接访问和修改类的状态
类和结构区别
在C++ 中将 C语言中 struct升级成了类,在C++中strcut也可以声明类。
- 结构(struct)默认访问类型是 public
- 类的默认访问类型是private
类的作用域
**类 **: 类的作用域是指类定义中声明的成员变量和成员函数的可见范围。类的作用域由类名和作用域解析运算符(::)共同控制。
类的实例化
类的实例化:指创建类的具体对象的过程。这个过程通常涉及到分配内存空间给新创建的对象,并设置其初始属性值。
例如:
class Stack { //类定义 }; int main() { Stack st; return 0; }
对象的大小
对象的大小类似于C语言中的结构体大小的计算方法。
- 第一个成员在与结构体偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的对齐数为8
- 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
class A1 { public: void f1(){} private: int _a; }; // 类中仅有成员函数 class A2 { public: void f2() {} }; // 类中什么都没有---空类 class A3 {};
- sizeof(A1) = 4
- sizeof(A2) = 1
- sizeof(A3) = 1
C++标准规定空类必须具有非零大小的原因主要有以下几点
- 确保对象地址唯一性:C++标准要求不同的对象不能具有相同的地址。如果空类的大小为0,那么在数组中连续创建多个空类对象时,这些对象将没有区分它们的内存空间,从而违反了这一原则.
- 避免指针运算问题:如果空类的大小为0,那么使用指针进行算术运算时将无法正确计算偏移量,因为除以0是非法的操作。这将导致编译器需要编写额外的代码来处理这些异常情况.
- 内存分配和对齐:新对象的分配需要不同的内存地址,且内存分配通常考虑到对齐要求。一个非零大小的空类可以确保即使是最基本的对象也至少占据一个内存单元,满足基本的内存对齐要求.
- 优化空间利用:C++标准允许空基类优化,即如果空类作为基类时不会与同一类型的另一个对象或子对象分配在同一地址,编译器可以选择不为其分配任何空间。这意味着空类的非零大小实际上不会增加派生类的内存占用,除非派生类本身需要更多空间.
三、this指针
this
指针是一个隐含的成员指针,它在类的非静态成员函数中可用,指向调用该函数的对象实例。
this
指针是一个常量指针,其指向的内容可以被修改,但指针本身不能被重新赋值。this
指针的类型是指向类类型的指针,即const ClassType*
。
this
指针在成员函数的整个执行期间都存在,其生命周期与函数的其他参数相同。this
指针不是对象内存的一部分,因此不会影响对象的大小
class A { public: void Print() { cout << "Print()" << endl; } private: int _a; }; int main() { A* p = nullptr; p->Print(); return 0; }
class B { public: void PrintB() { cout<<_a<<endl; } private: int _a; }; int main() { B* p = nullptr; p->PrintB(); return 0; }
- A会正常运行, 因为p调用的公共代码块的,没有进行成员访问。
- B段代码进行了成员访问,Print函数内部 this->_a。