
夏驰和徐策带你从零开始学习C++(面向对象的程序设计)
文章平均质量分 86
主要是对C++进行由浅入深的学习
夏驰和徐策
一个喜欢打游戏的计算机专业学生;这是我的GitHub:https://github.com/XiaChiandXuce
展开
-
P85 02 程序的内存模型—内存四区—全局区
全局区是存储全局变量和静态变量的内存区域。这些变量在程序启动时分配内存,并在程序结束时释放。与局部变量不同,全局变量和静态变量的生命周期贯穿整个程序的运行过程。全局区通常包括数据段(data segment)和BSS段(Block Started by Symbol)。原创 2024-06-28 11:13:48 · 1005 阅读 · 0 评论 -
P84 01 程序的内存模型—内存四区—代码区
代码区数据区栈区堆区这四个区域分别用于存储程序代码、全局变量和静态变量、局部变量以及动态分配的内存。代码区是C++程序内存模型中的一个重要组成部分,它存储程序的机器指令,并在程序的整个生命周期内保持不变。理解代码区的特点和作用有助于编写更高效、更安全的C++程序。在未来的博客中,我们将进一步探讨数据区、栈区和堆区,帮助大家全面理解C++程序的内存模型。通过掌握内存四区的知识,开发者可以更好地优化程序性能,避免常见的内存管理错误,提高程序的可靠性。希望这篇博客对你理解C++程序的内存模型有所帮助。原创 2024-06-28 10:31:00 · 1039 阅读 · 0 评论 -
2.5 指针和引用
指针是一种特殊的变量,具备一般变量的三个基本要素,但在类型和值上与一般变量有所不同。指针用于存放某个变量的地址值,因此,指针变量的数据值是某个变量在内存中的地址值。指针的类型是其所指向变量的类型,而不是指针本身的数据值类型。指针不仅可以指向各种类型的变量,还可以指向数组、函数、文件,甚至指向其他指针(即多级指针)。int a = 5;这里,定义了一个int型变量a,并初始化为5。定义了一个指针p,它指向int型变量a,其中&a表示变量a的地址值。定义指针时需要指定其类型,即在指针名前冠以,表示。原创 2024-06-27 18:48:13 · 1013 阅读 · 0 评论 -
4.9 函数模板
模板是一种工具,它是C++语言支持参数化多态性的工具。模板是用来解决代码重用的一种方法。代码重用就是按不同方式重复使用代码,因此,要求重用代码要有通用性,即不受使用的数据类型的影响。这种程序设计类型称为参数化程序设计,而模板就是用来解决这一问题的。模板实际上是对类型进行参数化。它是由可以使用和操作一定范围内的数据类型的通用代码构成的。总之,模板是对类型进行参数化的工具。模板通常有两种不同形式:函数模板和类模板。template (类型) () {原创 2024-06-27 09:55:52 · 731 阅读 · 0 评论 -
4.8 C++语言的系统函数
C++语言系统将所提供的系统函数的说明分类放在不同的头文件(.h文件)中。有关数学常用函数(如指数函数、对数函数、绝对值函数、立方根函数和三角函数及反三角函数等)放在math.h文件中。判断字母、数字、大写字母、小写字母等的函数放在ctype.h文件中。有关字符串处理的函数放在string.h文件中。屏幕处理函数放在conio.h中。图形处理函数放在graph.h中。了解所使用的C++语言系统提供了哪些系统函数。原创 2024-06-27 09:29:15 · 904 阅读 · 0 评论 -
4.7 作用域
在存在层次结构的作用域中,变量不能重复定义。这是指在相同的作用域内,不可有同名变量。但是,在不同的作用域内允许对某个变量进行重新定义。例如,在一个函数体内定义了分程序变量a,不能同时又定义一个同名变量a,但是可以在该函数体内的某个分程序中对变量a进行重新定义。int a;float a;这里有两个不同的变量名字都是a。按作用域的规则规定,int型变量a在整个函数fun内都是有效的、可见的。而float型变量a仅在定义它的分程序内是可见的,在该分程序前后的函数体内是不可见的。那么,int。原创 2024-06-27 08:56:24 · 833 阅读 · 0 评论 -
4.6 函数的嵌套调用和递归调用
但是,用递归方法编写的程序执行起来在时间和空间的开销上比较大,既要花费较长的计算时间,又要占用较多的内存单元,因为递归的过程中要占用较多的内存单元存放“递推”的中间结果。在调用B函数的过程中,还可以调用C函数。原有的问题能够分解为一个新的问题,而新的问题又用到了原有问题的解法,这就出现了递归。按照这一原则分解下去,每次出现的新问题是原问题简化后的子问题,而最终分解出来的新问题是一个已知解的问题。该阶段是从已知的条件出发,按照“递推”的逆过程,逐一求值回归,最后到达递推的开始处,结束回归阶段,完成递归调用。原创 2024-06-27 08:45:43 · 1023 阅读 · 0 评论 -
4.5 函数重载
在同一作用域内可以有一组具有相同名字但不同参数的函数。这被称为函数重载。函数重载的概念是:同一个函数名可以对应多个函数实现。例如,可以用函数名add定义多个函数,每个函数实现的功能是求和,即求两个操作数的和。一个函数实现是求两个整型数之和,另一个函数实现是求两个浮点型数之和,还有一个函数实现是求两个复数之和。每个函数对应着一个函数体。这些函数的名字相同,但是函数的参数类型不同。这就是函数重载的概念。函数重载要求编译器能够根据参数来区分函数,即采用不同的函数实现。原创 2024-06-27 08:36:57 · 308 阅读 · 0 评论 -
4.4 内联函数
内联函数的定义方法很简单,只要在函数定义的函数头前面加上inline关键字。内联函数的定义方法与一般函数一样。其中,inline是关键字。函数add_int()是内联函数。例4.13i原创 2024-06-27 08:33:04 · 435 阅读 · 0 评论 -
4.3 函数的参数
当一个函数带有多个参数时,C++语言没有规定在函数调用时实参的求值顺序。编译器根据对代码进行优化的需要自行规定对实参的求值顺序,有的编译器规定从左至右,有的编译器规定从右至左。这种对求值顺序的不同规定,对一般参数来说没有影响,但是如果实参表达式中带有副作用的运算符,就有可能由于求值顺序不同而产生二义性。其中,实参是两个表达式++x和x + y。如果编译器对实参求值的顺序是从左至右,则两个实参值分别为5和11。如果编译器对实参求值的顺序是从右至左,则两个实参值分别为5和10。由于实参值可能不同,调用。原创 2024-06-27 08:29:20 · 786 阅读 · 0 评论 -
4.2 函数的调用
函数定义后,就是为了将来对其进行调用。调用函数是实现函数功能的手段。如何调用函数是C++语言中的一个重要基础内容。C++语言中的函数调用比C语言更加丰富,C++不仅有传值调用(包括传变量地址值的传址调用),而且还有C语言中没有的引用调用。此外,C++语言还允许设置形参的默认值等。原创 2024-06-27 08:22:54 · 927 阅读 · 0 评论 -
4.1 函数的定义和说明
在讲述函数的定义和说明之前,先举一个由一个程序中分离出函数的简单例子。前面的例子分析了使用函数的方法。下面给出在C++语言中定义函数的一般格式。 () {其中,表示该函数的类型,即该函数返回值的类型。它可以是各种数据类型,包括基本数据类型和构造数据类型,也可以是指针和引用类型。如果该函数没有返回值,则其类型为void。与标识符的规定相同,函数名也是一种标识符。函数名最好做到“见名知意”。例如,sum_double表示浮点数求和的函数名。原创 2024-06-26 22:23:33 · 734 阅读 · 0 评论 -
9.7 流错误的处理
在对流进行操作时,特别是用流读写磁盘文件时,可能会发生错误。因此,必须有一种能够检测到错误状态的机制和清除错误的方法。例如,在打开一个文件时,若找不到这个文件或发生其他错误,就需要处理错误状态,使得流能够恢复正常处理。流对象的状态由一个状态字来记录,它用来表示各种错误或状态。该函数更多用于当流发生错误时清除流的错误状态,这时使用不带参数的。有时也可以用来设置流的状态错误,这时使用带参数的。用来清除和设置流的状态位,但它不能设置和清除。的错误状态位的程序。分析该程序的输出结果。以外的其他错误所设置的位。原创 2024-06-26 14:59:12 · 361 阅读 · 0 评论 -
9.6 字符串流
第一个构造函数使用所指定的串的全部内容来构造流对象,第二个构造函数使用串中前。类的构造函数所创建的对象是字符串读取流对象,可以从该对象中提取字符,并按其所规定的内部格式转换为不同类型的数据,存放到指定的变量中。类的构造函数所创建的是字符串插入对象,可以向该对象中写入若干不同类型的数据,并以字符文本形式存放在该对象中。其中,第一个构造函数是默认构造函数,用来建立存储所插入的数据的数组对象。类派生来的,用来将不同类型的信息格式化为字符串,并放到一个字符数组中。,它们使用的是不同的构造函数。原创 2024-06-26 14:53:13 · 863 阅读 · 0 评论 -
9.5 磁盘文件的输入和输出
在前面的章节中,我们已经讨论了流的读写操作,主要是针对文本流的操作。本节将介绍文件流的操作。文件流通常是指磁盘文件流。对磁盘文件流的操作通常是这样进行的:首先打开待操作的磁盘文件,打开后对文件进行读操作或写操作,文件读写操作所使用的读操作函数和写操作函数与前面讲的标准文件的读写函数相同。操作结束后,要关闭该文件。磁盘文件一般分为文本文件、二进制文件和随机文件。在进行随机文件操作时,还要进行文件中的读指针和写指针的定位操作。以上是磁盘文件的主要操作,这些就是本节讲述的主要内容。原创 2024-06-26 14:48:30 · 951 阅读 · 0 评论 -
9.4 格式化输入和输出
类的成员函数和流类库提供的操作子,C++程序员可以灵活地控制输入和输出的格式。这些功能使得数据的显示更加直观和易于阅读,增强了程序的可维护性和可读性。希望本文对C++ I/O流库中的格式化输入和输出有一个全面的理解,并为实际编程提供支持。C++语言的I/O流类库提供了多种方法来实现格式化输入和输出。这些方法主要分为两类:使用成员函数设置标志位和格式,以及使用流类库中提供的操作子。操作子是对象,可以直接被插入符或提取符操作。类的公有成员部分定义了一些格式控制常量和成员函数,使用它们可以对数据格式进行转换。原创 2024-06-26 11:27:09 · 809 阅读 · 0 评论 -
9.3 插入符和提取符的重载
重载插入符和提取符是C++语言的一个重要特性,它使得自定义的数据类型可以像内置类型一样方便地进行输入和输出操作。通过友元函数的使用,重载函数可以访问类的私有成员,从而实现更复杂的数据操作。希望本文对重载插入符和提取符的理解有所帮助,为编写更灵活、更易维护的C++程序提供支持。这样可以使自定义的数据类型像内置类型一样方便地进行输入和输出操作。类对象可以像内置类型一样进行输入和输出操作。在这个例子中,通过定义友元函数重载了插入符和提取符,使得。在这个例子中,通过定义友元函数重载了插入符和提取符,使得。原创 2024-06-26 11:20:41 · 313 阅读 · 0 评论 -
9.2 键盘输入
最常用的键盘输入方法是将提取符作用在标准输入流对象cin上。cin >> 表达式 >> 表达式 ...提取符可以连续写多个,每个后面跟一个表达式,通常是获得输入值的变量或对象。int a, b;return 0;输出结果(5, 6)在这个例子中,用户输入两个整数5和6,程序将它们分别存储在变量a和b中,并输出。原创 2024-06-26 10:50:08 · 290 阅读 · 0 评论 -
9.1 屏幕输出
最常用的屏幕输出方法是将插入符作用在标准输出流类对象cout上。return 0;输出结果这个例子展示了如何使用插入符将字符串的长度和大小输出到屏幕。cinistream类对象,用于标准输入(键盘输入)。coutostream类对象,用于标准输出(屏幕输出)。cerrostream类对象,用于标准出错信息输出(无缓冲区)。clogostream类对象,用于标准出错信息输出(带缓冲区)。原创 2024-06-26 10:43:05 · 837 阅读 · 0 评论 -
8.7 程序举例
通过以上两个例子,我们可以看到虚函数和多态性在实际编程中的重要应用。虚函数使得程序能够根据对象的实际类型调用相应的方法,从而实现了多态性。这种机制极大地提高了程序的灵活性和可扩展性,便于维护和扩展功能。希望本文对虚函数和多态性的理解有所帮助,为编写更灵活、更易维护的C++程序提供支持。该例子展示了一个宠物管理系统,假设一个人拥有20个宠物窝,一半用于养猫,另一半用于养狗。这个例子展示了虚函数的使用,使得对不同类型的动物有统一的操作接口,方便地进行多态操作。本节通过两个例子展示了多态性和虚函数的实际应用。原创 2024-06-26 10:31:34 · 315 阅读 · 0 评论 -
8.6 虚析构函数
在涉及多态性的编程中,基类的析构函数应被声明为虚函数,以确保通过基类指针或引用操作派生类对象时,能够正确调用派生类的析构函数,从而避免资源泄漏和未定义行为。这是因为通过基类指针或引用操作派生类对象时,如果没有虚析构函数,析构过程将无法正确完成,导致资源泄露。运算符删除一个对象时,能够正确调用析构函数,从而采用动态联编的方式选择析构函数,确保对象的删除更彻底。如果一个基类的析构函数被声明为虚析构函数,则其派生类的析构函数也是虚析构函数,不管它是否使用关键字。的析构函数,释放了动态分配的资源,然后再调用基类。原创 2024-06-26 10:27:08 · 363 阅读 · 0 评论 -
8.5 纯虚函数和抽象类
纯虚函数和抽象类是C++中实现面向对象编程的重要工具。抽象类通过定义一组共同的操作接口,组织相关的类,并提供一个公共的继承层次,为面向对象设计提供了强有力的支持。抽象类的主要作用是将有关的类组织在一个继承层次的结构中,为它们提供一个公共的根。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,处于继承层次结构的上层。在许多情况下,基类中的虚函数不需要提供具体实现,而是将其声明为纯虚函数,并将实现留给派生类去完成。类的指针,这实现了动态联编,程序在运行时选择相应的函数实现。类实现了函数的计算逻辑,而。原创 2024-06-26 10:23:20 · 390 阅读 · 0 评论 -
8.4 虚函数
virtual ();在某个类中,如果某个成员函数被声明为虚函数,这意味着该成员函数在派生类中可以被重写。当通过基类指针或引用调用该成员函数时,将采用动态联编方式,即在运行时确定调用的具体函数实现。原创 2024-06-26 10:18:44 · 305 阅读 · 0 评论 -
8.3 静态联编和动态联编
静态联编和动态联编是程序设计中两种重要的联编方法。希望本文对静态联编和动态联编的理解有所帮助,为编写更高效、更灵活的C++程序提供支持。从对静态联编的上述分析中可以知道,编译程序在编译阶段并不能确切知道将要调用的函数。这就是动态联编,又叫晚期联编或动态绑定。联编是指计算机程序将函数的代码与程序本身关联的过程。根据联编所进行的阶段不同,可分为静态联编和动态联编。静态联编是指在编译连接阶段完成的联编,因此又称为早期联编或静态绑定。静态联编适用于性能要求高的场景,而动态联编适用于需要多态性和灵活性的场景。原创 2024-06-26 10:13:24 · 466 阅读 · 0 评论 -
8.2 运算符重载
运算符重载是C++语言中的一个强大特性,能够使程序更加简洁和易读。通过重载运算符,可以实现自定义数据类型的自然操作,如复数的加减乘除、数组的安全访问等。重载运算符应保持其原有的优先级和结合性。重载运算符的含义应清晰明确,避免二义性。根据需求选择合适的重载形式,成员函数形式和友元函数形式各有优缺点。通过合理使用运算符重载,可以极大地提高程序的可读性和可维护性,同时也增强了C++语言的表达能力。原创 2024-06-26 10:08:55 · 1019 阅读 · 0 评论 -
7.5 应用示例
下面是一个有关日期(年、月、日)和时间(时、分、秒)的程序。该程序建立了三个类,分别是日期类、时间类和基于前两个类派生的日期和时间类。程序说明输出结果:说明:程序包含的头文件:类型定义: 该语句定义了一个新的类型,它是型的一维数组,有80个元素。类关系: 程序中定义了三个类:、和。类通过多继承继承了类和类。关系图如下: 构造函数:成员函数:本实例通过多继承实现了日期和时间的组合,展示了继承和成员函数的使用方法。通过使用定义新类型和格式化字符串,使得代码更加简洁和易读。通过这种方式原创 2024-06-25 22:50:19 · 362 阅读 · 0 评论 -
7.4 虚基类
在该结构中,类A是类C的公共基类,在派生类中访问公共基类的成员时可能出现二义性,需要用适当的类名限定加以避免。于是,只有用于建立对象的那个最派生类的构造函数调用虚基类的构造函数,而该派生类的直接基类中所列出的对这个虚基类的构造函数调用在执行中被忽略,这样便保证了对虚基类的子对象只初始化一次。在建立类D对象时,只有类D的构造函数的成员初始化列表中列出的虚基类构造函数被调用,并且仅调用一次,而类D的基类的构造函数的成员初始化列表中列出的虚基类构造函数不被执行。指针指向类D的对象,这是正确的,并且也无二义性。原创 2024-06-25 22:43:51 · 860 阅读 · 0 评论 -
7.3 多继承
因此,执行基类构造函数的顺序取决于定义派生类时基类的顺序。处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。在程序中创建类C的对象时,类A的构造函数被调用两次,一次是类B1调用的,另一次是类B2调用的,以此来初始化类C对象中包含的两个类A的成员。按多继承的规定,派生类C的成员包含了基类A中的成员和基类B中的成员以及该类本身的成员。但是,由于在多继承情况下,可能出现对基类中某个成员的访问不唯一的情况,这称为多继承的二义性问题。原创 2024-06-25 22:36:44 · 907 阅读 · 0 评论 -
7.2 单继承
如果A类型是B类型的子类型,那么B类型必将适应于A类型。派生类的构造函数中需要包含基类的带参数的构造函数时,派生类构造函数显式包含基类的带参数的构造函数。该程序中,派生类B内定义了三个构造函数,前两个构造函数没有显式地调用基类构造函数,其实它们却隐式地调用了基类A中的默认构造函数,由于不需要任何参数,所以可在派生类的构造函数的定义中省去对它的调用。其中,B是派生类构造函数名,它的总参数表中有3个参数:参数i用来初始化基类的数据成员,参数j用来初始化类B中的子对象aa,参数k用来初始化类B中的数据成员b。原创 2024-06-25 22:15:50 · 675 阅读 · 0 评论 -
7.1 基类和派生类
在面向对象编程中,通过继承可以在一个已有类的基础上创建一个新的类。这个新类不仅继承了已有类的成员,还可以定义属于自己的新成员。已有的类称为基类,而新定义的类称为派生类或子类。派生类通过继承基类的成员和方法,实现了代码的重用性和扩展性。通过单继承和多继承,程序设计者可以灵活地构建复杂的类层次结构,满足不同的编程需求。接下来,我们将详细讨论不同的继承方式及其对访问权限的影响。派生类只能访问公有继承方式下基类中的公有成员。派生类的派生类可以访问公有继承和保护继承方式下基类中的公有成员和保护成员。原创 2024-06-25 22:00:44 · 1021 阅读 · 0 评论 -
6.7 应用示例—链表
显示链表插入链表项追加链表项连接两个链表逆向输出链表项计算链表长度该程序应用了类和对象的许多基本知识,如类的定义、对象的定义、构造函数及其重载、子对象指针、友元类以及使用new动态创建对象。这些操作为编写更复杂的链表操作打下了基础。如果有兴趣,读者可以进一步完善该程序,添加删除、修改和查询功能。原创 2024-06-25 16:44:03 · 388 阅读 · 0 评论 -
6.6 类模板
class 类名 {// 类体template关键字用于定义类模板,表示模板参数。模板参数可以有多个,用逗号分隔。原创 2024-06-25 16:38:19 · 319 阅读 · 0 评论 -
6.5 类型转换
通过这些示例,我们可以看到类型转换在 C++ 中的多种应用及其实现方法。类型转换是将一种数据类型的值转换为另一种数据类型的值。类型转换函数是类中的非静态成员函数,用于将类的对象转换为其他类型的值。当类定义中提供了单个参数的构造函数时,该类可以将某种数据类型的值转换为该类的对象。当函数有返回值时,系统会自动将返回表达式的类型转换为函数的返回类型。在赋值表达式中,右边表达式的值自动转换为左边变量的类型。在函数调用时,实参值会自动转换为形参的类型。在算术运算中,低类型可以自动转换为高类型。在这个例子中,整型数。原创 2024-06-25 16:32:40 · 277 阅读 · 0 评论 -
6.4 子对象和堆对象
int b;在上述例子中,类B中的成员a就是子对象,它是A类的对象作为B类的成员。原创 2024-06-25 16:01:11 · 488 阅读 · 1 评论 -
6.3 常类型
或者这两种写法是等价的,都是定义了一个值为2的整型常量x。常数组是指数组中的元素都是常量,不能被修改。这里,数组a的每个元素都是int类型的常量。类型 函数名(参数表) const;原创 2024-06-25 15:51:03 · 365 阅读 · 0 评论 -
6.2 对象数组和对象指针数组
类名> [];这表示dates是一个包含7个DATE类对象的一维数组。原创 2024-06-25 15:42:48 · 602 阅读 · 0 评论 -
6.1 对象指针和对象引用
对象引用的使用更简洁直观,同时也具有指针的传址调用特性,从而在 C++ 编程中得到了更广泛的应用。本节讲述指向对象的指针和对象的引用这两个概念及其在 C++ 编程中的应用。程序中使用了两种不同的指针:一种是指向对象的指针,另一种是指向类成员的指针。在 C++ 中,指向类成员的指针包括指向类的数据成员和指向成员函数的指针。使用指向对象的指针通过指向类成员的指针对该成员进行操作时,可使用运算符。也可以使用对象来调用指向类成员函数的指针所指向的成员函数。类的一个对象,然后通过对象来引用指针所指向的成员。原创 2024-06-25 15:28:50 · 1165 阅读 · 0 评论 -
5.9 对象的生存期
对象的生存期是指对象从被创建开始到被释放为止的存在时间。原创 2024-06-24 23:45:51 · 260 阅读 · 0 评论 -
5.8 局部类和嵌套类
局部类和嵌套类在C++中提供了一种更细粒度的封装和作用域控制机制。局部类在函数内定义,用于限制类的作用域在函数内部,而嵌套类则在类内定义,用于实现更复杂的类结构和数据封装。这些特性有助于更好地管理代码的复杂性和安全性,但需要注意使用场景和限制。原创 2024-06-24 23:43:19 · 341 阅读 · 0 评论 -
5.7 类的作用域
类的作用域简称类域,是指在类的定义中由一对花括号括起来的部分。每一个类都具有该类的类域,该类的成员属于该类的类域中。从前面讲述的类的定义中可知,在类域中可以说明变量,也可以说明函数。然而,类域又不同于文件域,在类域中说明的变量不能使用。一般来说,类域介于文件域和函数域之间。由于类域问题比较复杂,在前面和后面的程序中都会遇到,因此只能根据具体问题具体分析。文件域中可以包含类域,显然,类域小于文件域。一般来说,类域中可包含成员函数的作用域,类域又比函数域大。声明在类体内,但它的作用域属于类。原创 2024-06-24 23:37:24 · 306 阅读 · 0 评论