2.C++核心编程
文章平均质量分 61
主要介绍面向对象的编程。包括动态内存的使用、引用、函数重载、类和对象及IO操作
123_YQH
努力不秃头!
展开
-
12.动态内存
动态内存C++内存分为四个区:代码区:存放函数体的二进制代码。全局区(静态区,常量区):全局变量和静态变量都存储在全局区,全局对象在程序启动时创建,程序结束时销毁;局部static在第一次使用时被创建,在程序结束时销毁。栈区:栈区用来存放局部变量,局部变量在块内所定义的地方被创建,在离开块时被销毁。堆区:堆区用来存放动态内存,动态内存对象的生存期被程序控制,必须程序员自己区销毁它。本章先介绍直接管理内存(new在堆区开辟动态内存,delete来释放开辟的空间),由于直接管理内存很容易出错,接原创 2021-09-10 16:36:18 · 72 阅读 · 0 评论 -
12.1new和delete直接管理动态内存
new和deletec++定义了两个运算符来分配和释放动态内存。new来分配内存,delete来释放内存。1.new分配内存①动态内存的分配和初始化动态分配的内存是无名的,返回一个指向这块内存的指针。 动态内存初始化的方式有三种:默认初始化: 内置类型按内置类型初始化规则初始化,在所有块之外初始化为0,在任何块之内则是未定义的;自定义的类型采用其默认构造函数初始化。直接初始化: 动态开辟的对象会初始化,建议采用这种初始化方式列表初始化: 对vector、数组这种适合使用列表初始化int原创 2021-09-10 17:43:54 · 143 阅读 · 0 评论 -
13.1拷贝、赋值和销毁
拷贝、赋值和销毁当定义一个类时,我们显式或隐式地指定再次类型地对象拷贝、移动、赋值和销毁时做什么,这些操作统称为拷贝控制操作,主要包括:拷贝构造函数拷贝赋值运算符移动构造函数移动赋值运算符析构函数如果我们没有显式定义这些操作,编译器会自动默认定义这些操作。1.拷贝构造函数如果一个构造函数地第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此参数是拷贝构造函数。 如:class Foo {public: Foo(); //默认构造函数 Foo(const Foo&am原创 2021-10-25 21:36:30 · 175 阅读 · 0 评论 -
13.2拷贝控制和资源管理
通常,管理类外资源的类必须定义拷贝控制成员。这种类需要通过析构函数来释放对象所分配的资源,根据三五法则,需要析构函数的类也必须定义拷贝构造函数和拷贝赋值运算符。我们先来看管理类型的对象的拷贝语义。一般来说有两种选择:类的行为像一个值。意味着它应该也有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立得。改变副本不会对原对象有任何影响,反之亦然。如string类,管理类外的字符串类型。类的行为像一个指针。行为像指针得类则共享状态*。当我们拷贝一个这种类得对象时,副本和原对象使用相同的底层数原创 2021-10-26 11:48:03 · 164 阅读 · 0 评论 -
13.4对象移动
对象移动很多情况下都会发生对象拷贝。在其中某些情况下,对象拷贝后就立即销毁了。在这些情况下,如果对象较大或者对象本身要求分配空间(如string),进行不必要的拷贝代价非常高。移动而非拷贝对象会大大提升性能。就像1.右值引用为了支持移动操作,C++11引入了一个新的引用类型——右值引用。右值引用就是必须要绑定到右值的引用,通过 && 而不是&来获得右值引用。①左值和右值C++中所有的值必属于左值、右值两者之一:左值:可以取地址的、有名字的就是左值。如:变量表达式a原创 2021-10-27 22:07:17 · 218 阅读 · 0 评论 -
14.1重载运算符基本概念
运算符运算与类型转换概述当运算符被用于类类型的对象时,C++允许我们为其定义新的含义。明智的使用运算符重载能使我们的程序更易于编写和阅读。1.基本概念重载的运算符是具有特殊名字的函数:它们的名字由operator加要定义的类型组成,如重载Sales_item的=运算符:Sales_data& operator=(const Sales_data &);的函数名字为operator=。重载运算符函数的参数数量和该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个。原创 2021-10-29 17:07:18 · 158 阅读 · 0 评论 -
14.2输入和输出运算符
输入和输出运算符IO标准库通过<<和>>为内置类型定义了读写的版本,而类需要自定义合适其对象的新版本以支持IO操作。1.重载输出运算符<<①输出运算符的形参:第一个形参是一个非常量ostream对象的引用。非常量是因为需要向流写入内容,这会改变其状态;引用是因为我们无法拷贝一个ostream对象,只能对其进行引用。第二个形参是一个常量引用,是我们想打印类对象的内容,引用避免进行拷贝,而且我们不希望改变其内容,所以用常量引用。类似其他内置类型的<<原创 2021-11-01 11:28:46 · 557 阅读 · 1 评论 -
14.3算数和关系运算符
算数和关系运算符1.算数运算符通常情况下,我们把算数和关系运算符定义成非成员函数,因为一般来说算数和关系运算符对象都是对称的,可以左右互换;并且由于这些运算符不需要改变对象的状态,因此参数应设置为常量引用。一般来说,算数运算符也会定义一个对应的复合运算符。通常情况下应该使用复合运算符形式来实现算数运算符。如:Sales_data的加号运算符//Sales_data类class Sales_data { friend istream& operator>>(istrea原创 2021-11-01 14:58:29 · 229 阅读 · 1 评论 -
14.4递增和递减运算符
递增和递减运算符定义递增和递减运算符的准则:①定义递增和递减运算符的类应该同时定义前置和后置版本。②递增和递减运算符应该被定义成成员函数③前置运算符应该返回递增或递减后对象的引用,后置运算符应该返回对象的原值(递增或递减前的值)而非引用。④区分前置和后置运算符:前置版本与正常的运算符重载形式类似。后置版本参数列表接受不被使用的int类型形参,这个形参唯一的作用就是区分前置和后置类型版本。例如:开发一批苹果手机,每个有一个编号,每个手机除了编号外其余所有参数一致。可以为其定义递增或递减运算原创 2021-11-01 15:32:50 · 202 阅读 · 1 评论 -
15.1面向对象程序设计概述
面向对象程序设计概述面向对象程序设计基于三个基本概念:数据抽象(封装)、继承和动态绑定(多态)。继承和多态对程序的编写有两方面的影响:我们可以更容易地定义与其他类相似但不完全相同的类。在使用这些彼此相似的类编写程序时,我们可以在一定程度上忽略掉它们的区别。例如:输掉中不同书籍的定价策略可能不同:有的书籍按原价销售,有的打折销售等等。面向对象的程序设计适用于这类应用。1.继承通过继承联系在一起的类构成一种类似于树的层次关系。通常在层次关系的根都有一个基类(父类),其他类则直接或间接从基类继承原创 2021-11-03 16:59:54 · 295 阅读 · 1 评论 -
15.2定义基类和派生类
定义基类和派生类我们首先完成基类和派生类的定义:我们首先定义了一个名为Quote的类作为基类表示按原价销售的书籍,Bulk_quote的类作为派生类表示可以打折销售的书籍。这些类包含两个函数:isbn()表示书籍的ISBN编号,netPrice()表示实际出售的价格。class Quote {public: Quote() = default; Quote(const string &s, double d):_isbn(s), _price(d){} virtual原创 2021-11-03 21:16:54 · 1314 阅读 · 0 评论 -
15.3类型转换与继承
类型转换与继承理解基类与派生类的类型转换是理解C++语言面向对象编程的关键所在。通常引用或者指针绑定的对象应与对象类型一致,或者含有一个可接受const类型的转换规则。但是继承关系的类是一个例外:我们可以将基类指针或引用绑定到派生类对象上。这隐含了一层重要的意义:当使用基类指针或引用时,我们不清楚该引用或指针所绑定对象的真实类型,可能是基类对象也可能是派生类对象。1.静态类型与动态类型首先我们得先明确几个名词的定义:静态类型:对象在声明时采用的类型,在编译期确定,它是变量声明时的类型或表达式生原创 2021-11-03 21:53:22 · 131 阅读 · 0 评论 -
15.4虚函数
虚函数当我们使用基类的指针或引用调用一个虚函数成员时,会执行动态绑定。因为我们直到运行时才知道调用的哪个虚函数,所以需要为所有虚函数都定义。通常,如果我们不使用某个函数,则无需为其定义,但是虚函数必须要定义,因为不知道会调用哪个虚函数,所以都要准备。1.对虚函数的调用可能在运行时才被解析当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的函数。被调用的函数是与绑定到指针或引用上的对象的动态类型相匹配的那一个。如:Quote base("abc", 50);prin原创 2021-11-04 11:38:25 · 143 阅读 · 0 评论 -
15.5抽象基类
抽象基类假设书店有几种不同的折扣策略,除了购买量超过一定数量享受折扣外;也有购买量不超过某个限额可以享受折扣,但超过就会原价销售;还有不超过某个购买数量原价销售,超过某个数量超出的部分才打折。上面这些打折策略都要求一个购买量和一个折扣值。我们可以定义一个DiscQuote类来支持不同的打折策略,DiscQuote类的意义就是打折的概念类。负责保存购买量的值和折扣值。其他类表示某种特定的打着策略类,将继承DiscQuote类。DiscQuote类与任何特定的折扣策略都无关,因此DiscQuote类的ne原创 2021-11-04 16:41:24 · 139 阅读 · 0 评论 -
15.6访问控制和继承
访问控制与继承每个类分别控制自己的成员初始化过程,每个类还分别控制着其成员对于派生类是否可访问。基类的protected成员只有基类和派生类成员和友元能访问,而private成员只有基类成员和友元能访问①受保护的成员一个类使用protected关键字声明那些派生类可以分享但是不能被其他公共访问使用的成员。protected有以下规则:和私有成员类似,受保护的成员对类的对象来说是不可访问的。和公有成员类似,受保护的成员对于派生类的成员和友元是可访问的。派生类的成员和友元只能访问派生类对象中的基原创 2021-11-04 21:24:43 · 195 阅读 · 1 评论 -
15.7继承中的类作用域
继承中的类作用域①派生类的作用域嵌套在基类作用域中每个类定义自己的作用域,在这个作用域内我们定义类的成员。当存在继承关系时,派生类和基类的作用域会发生嵌套,派生类的作用域嵌套在基类的作用域之中。 如果一个名字再派生类的作用域中无法正确解析,则编译器将继续再外层的基类作用域中寻找改名字的定义。如://isbn在基类Quote中,DiscQuote是Quote的派生类,BulkQuote是DiscQoute派生类BulkQuote bulk;cout << bulk.isbn();名原创 2021-11-04 22:15:00 · 195 阅读 · 0 评论 -
15.8构造函数与拷贝控制
构造函数与拷贝控制和其他类一样,继承体系中的类也需要控制自己的拷贝控制操作,包括:拷贝构造、拷贝赋值运算符、移动、析构。如果一个类(不管是基类还是派生类)没有定义拷贝控制操作,编译器会为它合成一个版本。1.虚析构函数①基类通常应该定义一个虚析构函数,这样就能动态分配继承体系中的对象了当我们delete一个动态分配的对象的指针时将执行析构函数,但如果该指针指向继承体系中的某个类型,就可能出现指针的静态类型和被删除对象的动态类型不符合的情况。例如:Quote *itemp = new Quote;原创 2021-11-05 13:22:12 · 155 阅读 · 0 评论 -
15.9为什么要将成员变量设置为private
代码】4.1.4为什么要将成员变量设置为private。原创 2022-07-27 22:23:28 · 1721 阅读 · 0 评论 -
16.1定义模板
定义模板模板是泛型编程的基础,容器、迭代器和算法都是模板的例子。一个模板就是一个创建类或函数的蓝图或者公式。假定希望编写一个函数来比较两个值,并指出第一个值是小于、等于还是大于第二个值。在实际中,我们可能想要定义多个函数,每个函数比较一种给定类型的值。//如果两个值相等返回0,如果v1小于v2返回-1,否则返回1int compare(const string &v1, const string &v2) { if (v1 < v2) return -1; if原创 2021-11-08 21:05:42 · 201 阅读 · 0 评论