一,学习内容概述
二,所学内容的使用
(一)递归算法:
递归:程序直接或者间接的调用自身。其关键在于找出递归定义和终止条件。
1.通过递归调用将整个问题层层分解成处理方法相似的子问题;
2.通过回溯,按照递归关系将子问题的解整理成整个问题的解;
3.分解子问题时,如当前问题有多种情况需要考虑,要进一步进行枚举;
(二)复合数据类型:
1.结构体
- 结构体:由一系列具有相同类型或者不同类型的数据构成的数据集合。
- 结构体的声明:
struct student{
string name;
char sex;
int age;
};//注意此处分号!!!
- 结构体的使用
(1)可以对结构体变量的整体进行部分操作。比如:swag(a,b)(注意:a和b两个变量要为同种类型)。
(2)对结构体变量的成员进行操作:
格式:结构体变量名. 成员名 - 结构体的扩展:
(1)运算符重载:
类型名 operator 运算符(const 类型名 变量)const{
……
}
(2)成员函数:
struct student{
string name;
char sex;
int age;
void input(){cin>>name>>sex>>age;}//成员函数
}
2,标准库string
- string定义:string表示可变长度的字符序列。
- string的基本使用:
string s1, s2; //创建两个空字符串对象
string s3 = "Hello, World!"; //创建s3,并初始化
string s4("I am ");
s2 = "Today"; //赋值
s1 = s3 + " " + s4; //字符串连接
s1 += " 5 "; //末尾追加连接
s4(n,'c');//把s4初始化为由连续n个c字符组成的串
cout << s1 + s2 + "!" <<endl; //输出字符串内容
cout <<"Length of s1 is :" << s1.size() << endl;
//s1的长度,包含的元素个数
for (size_t i = 0; i < s1.size(); ++i)
cout << s1[i] <<" ";
}//逐个输出
- string的读写:使用标准库中iostream可以读写string对象。
键盘输入时,遇到空格或回车结束。
(1)可以用循环读取未知数量的string对象
//读取输入流中的单词,直到文件结束
string word;
while(cin >> word)//有效输入返回true
cout << word << endl;
(2)getline()函数。得到一段完整的文本,遇到回车结束。
注意:
a.两个参数:输入流对象和存放读入字符串的string对象
b.返回参数输入流对象
//每次读取一行文本,直到文件结束
string line;
while(getline(cin, line))
cout << line << endl;
(3)判断string对象是否为空。
empty()函数判断string对象是非为空,返回一个布尔值。
//每次读取一行文本,输出非空的行
string line;
while(getline(cin, line))
if(!line.empty()) //line不为空,输出
cout << line << endl;
(4) 比较string对象。
相等:程度相同且所包含字符也完全相同。
依照字典顺序比较。
(5)string对象的赋值和连接
运算符“+”连接。
"+"运算符要求至少有一个运算对象是string。
3.指针和引用
- 指针
(1)直接与间接访问:通过变量名直接访问;通过指针间接访问。
(2)指针与指针变量:指针为一个变量的地址;指针变量为存放变量地址的变量。指针变量的数据类型是,32位无符号整数。
(3)指针变量的定义:
格式:类型 *指针变量;(类型为所绑定目标变量的类型)
目标变量的地址和指针变量的绑定,通过取地址运算符&
int ival = 120;
int *pi = &ival;
//初始化,取出ival的地址赋值给pi; pi存放int变量ival的地址
// 或者说pi指向ival
(4)指针解引用运算符*
若一个指针指向一个对象,则可以间接访问该对象,通过使用指针解引用运算符
int x = 100, y = 20;
int *pi = &x;
*pi = y;
// 取内容,间接操作pi指向的x,即x = y,不是pi指向y
(5)指向对象的指针
指向对象的指针与两个存储单元关联:
一是指针自己的存储单元(里面存放在所指向对象的地址);二是指针指向对象的存储单元(里面存放着该对象的值)。
(6)指针的类型:即为指针指向的目标变量的类型。
(7)指针的值:指针不能存放非地址值,也不能被赋值或者初始化为不同类型的地址值。
(8)空指针:不指向任何对象的指针
//生成空指针的两种方式
int *p1=0;
int *p2=NULL;
(9)指针的用法——动态存储空间的分配
动态存储空间的管理:
方法:new ,delete
A. new运算符:堆上动态分配空间,创建对象,并返回对象的地址(一般返回的地址保存在指针变量中)。
int* ip1 = new int;
//在堆上分配一个int类型的对象,返回它的地址
*ip1 = 512;
//堆上分配的这个对象只能通过指针间接操作
int* ip2 = new int(100);
//在堆上分配一个int对象,
//初始化为100,实参,分配一个空间,返回其地址
int* ipa = new int[100];
//在堆上分配一个大小为100的int数组并返回数组的首地址,分配若干个空间
B.delete运算符:堆上的空间使用后必须回收,否则会造成内存泄漏。
int* ip = new int;
... //不再使用这个int对象时,释放内存
delete ip;
//释放指针指向的int对象,将空间归还给动态存储区
int* pa = new int[100];
... //不再使用这个数组时,释放内存
delete[] pa;
//释放指针pa指向的数组,将空间归还给动态存储区
空悬指针:ip指针在执行delete后,绑定关系解除,不能再使用ip指向内存,但指针变量本身存在,数据也存在。ip不是空指针,是空悬指针,即指向不确定的单元,delete后不可以通过ip间接使用这个单元。
- 引用
(1)引用又称别名,即对象的另一个名字。
(2)引用的定义与初始化:
格式:type & refVariable=leftValue;
引用必须初始化,初始化值为一个有内存地址的对象。
一旦初始化完成,引用将和它的初始化对象一直绑定,无法重新绑定另一个对象。
int ival = 100;
int &refVal = ival;
int x = 100, y = 20;
int &r = x; // r是x的引用
r = y; // x = y;x=20
- const限定指针
(1)指向const对象的指针:
const type * cp; 或者 type const * cp;
cp是指向常量的指针,它所指向的内存中的内容不可以改变,即*cp的值不能改变
const int ival = 1024;
const int *pi = &ival; //OK
//或者这样写:
int const *pi = &ival; //OK
*pi = 500;
//错误:因为*pi是一个const int,常指针
(2)指向非const对象的指针:
type* const cp = initAddressValue;
cp是常量指针,初始化后值不能改变,指向固定的单元
int ival = 1024;
int* const pi = &ival;
(3)指向const对象的const指针:
const type* const cp = initAddressValue;
cp是常量指针,且指向常量。
const int ival = 5;
const int* const pi = &ival;
- const限定的引用
(1)const引用可以绑定到const对象
不能用非const引用指向const对象
const int ival = 5;
const int &r1 = ival;
//正确:引用和所引用的对象都是const int
r1 = 10;
//错误:r1是const的引用,不能修改
int &r2 = ival;
//错误:不能用非const引用指向const对象
(2)const引用可以绑定到非const对象
但是const引用不能用来修改它所绑定的对象
int ival = 10;
const int &r1 = ival;
//正确:允许将const引用绑定到非const对象上
ival = 20; //正确
r1 = 20; //错误:r1是const引用,不能修改
(三)类与对象
1.类相关概念
- 类:对具有相同属性和行为的一类客观事物的描述。是用户自定义的数据类型。
类包括行为(成员函数)和属性(数据成员)。
类的定义格式:
class 类名{
public://公有
protected://保护
private://私有
};//注意:此处分号不可以省略!!!!类定义以分号结束! - 对象:对象是类的实例或者实体。
对象是具体化的,类是抽象的。
对象的定义格式:
类名 对象名1,对象名2,…,对象名n;
(先定义类,再定义对象。) - 访问权限:public公有的;protected受保护的;private私有的
- 类与结构体的区别:
没有明确指定类成员的访问权限时,C++结构体的成员都是公有的,而类的成员是私有的。 - 类成员的访问(两种方式):
(1)对象名 . 公有成员
(2)指针访问形式:对象指针变量名->公有成员 - this指针:(this表示当前对象)
显式引用 this指针的三种情况
(1)在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
(2)当参数与成员变量名相同时,如this->x = x,不能写成x = x。
(3)避免对同一对象进行赋值操作
2.类的特殊成员函数:
-
构造函数
-
析构函数
-
复制构造函数:
语法形式
类名 :: 类名(const 类名 & 引用名 , …);
(形参)参数是同类对象,
要求有一个类类型的引用参数。
(1)浅复制:
在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容
(2)深复制:
一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源
定义:类名::类名([const] 类名 &对象名); -
重载函数:重载为函数名相同,但参数(个数,类型)不同。
3.类的其他成员
-
常成员
(1)常数据成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变。构造函数就只能通过初始化列表对该数据成员进行初始化。
(2)常对象:
说明形式如下:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
在定义常对象时必须进行初始化,而且不能被更新。
(3)常成员函数:
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数(对数据成员只读不写)
格式如下:
类型说明符 函数名(参数表) const; -
静态成员
(1)静态数据成员:
公有访问权限的静态成员,可以通过下面的形式进行访问:
类名::静态成员名字
对象名.静态成员名字
对象指针->静态成员名字
在静态成员函数内部,直接访问。
静态数据成员声明及初始化:
类型 类名::静态数据成员[=初始化值]; //必须进行声明
不能在成员初始化列表中进行初始化
2)静态成员函数
静态成员函数和静态数据成员都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
静态成员函数没有this指针,只能对静态数据操作
定义静态成员函数的格式如下:
static 返回类型 静态成员函数名(参数表);
调用公有静态成员函数的一般格式:
类名::静态成员函数名(实参表)
对象. 静态成员函数名(实参表)
对象指针->静态成员函数名(实参表) -
友元 (一般不使用,破坏了封装性)
(1)友元函数
如果在本类(类A)以外的其他地方定义了一个函数(函数B)
类体中用friend对其(函数B)进行声明,此函数就称为本类(类A)的友元函数。
(2)友元类
若F类是A类的友元类,则F类的所有成员函数都是A类的友元函数
声明:friend class 类名;
4.类的组合
当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;
(四)运算符重载
1.运算符重载事物限制:
不改变运算符的优先级,结合性
不改变运算符所需要的操作数
不能创建新的运算符
2.用成员函数或友元函数重载运算符
-
(1)一元运算符
Object op或 op Object
重载为成员函数,解释为:
Object . operator op ()//调用重载运算符的函数
操作数由对象Object通过this指针隐含传递
重载为友元函数,解释为:
operator op (Object)
操作数由参数表的参数Object提供 -
(2) 二元运算符
ObjectL op ObjectR
重载为成员函数,解释为:
ObjectL . operator op ( ObjectR )//第一个操作数默认为当前操作数
左操作数由ObjectL通过this指针传递,右操作数由参数ObjectR传递
重载为友元函数,解释为:
operator op ( ObjectL, ObjectR )
左右操作数都由参数传递 -
(3)用成员函数重载运算符
- 双目运算符重载为成员函数
对双目运算符,形参表中仅有一个参数,它作为运算符的右操作数
- 双目运算符重载为成员函数
-
单目运算符重载为成员函数
对单目运算符,形参表里没有参数 -
(4)用友元函数重载
友元函数重载运算符常用于运算符的左右操作数类型不同的情况
3.几种典型的运算符重载
-
(1)重载赋值运算符:
operator= 必须重载为成员函数
重载函数原型为:
类名 & 类名 :: operator= ( 类名 ) ; -
(2)[]下标运算符重载
用于访问数组对象的元素(取元素)
格式:类型 类名::operator [] (形参); -
(3)()调用运算符重载
用于函数调用
格式:类型 类名 :: operator() ( 形参 ) ; -
(4)重载流插入和流提取运算符
-
用友元函数重载 << 和 >> ,输出和输入用户自定义的数据类型
只能被重载成友元函数
定义输出运算符“<<”重载函数的一般格式:
ostream& operator<<(ostream& out,class_name& obj)
{//返回值类型为流对象
out<<obj.item1;
out<<obj.item2;
… .
out<<obj.itemn;
return out;
}
istream& operator>>(istream& in,class_name& obj)
{
in>>obj.item1;
in>>obj.item2;
. . .
in>>obj.itemn;
return in;
}
三,需要注意的细节
(一)递归
优化方法:记忆化搜索(记录已经求出来的结果),特点:空间换时间。
(二)复合数据类型注意事项
1,结构体
(1)注意结构体{}后的分号
(2)对结构体变量的整体操作仅限于变量的数据类型相同,一般不能整体操作。
2,标准库string
(1)string在键盘输入时,遇到空格或者回车结束。
(2)getline函数得到一完整的文本,遇到回车结束。
格式:getline(输入流对象,存放读入字符串的string对象)
3,指针和引用
-
指针:
(1)指针与指针变量:指针为一个变量的地址;指针变量为存放一个变量地址的变量。
(2)定义指针时,一定要有具体指向,应该对指针进行初始化。
(3)空指针≠空悬指针。
空指针:不指向任何对象的指针。
空悬指针:指向不确定的单元。
delete后,不可以通过空悬指针对空间间接使用,会引起不可预料的运行错误。 -
引用
(1)引用必须初始化,引用只能绑定到有地址的对象上,不能和计算值或者某个表达式的计算结果绑定在一起。 -
指针vs引用
(1)定义形式:
指针:类型* 指针变量;(可以多次绑定)
引用:类型&引用名=初始值;(只在初始化时绑定)
(2)使用方式:
指针:通过 取内容* 间接访问
引用:引用是对象的别名,可以直接访问
(3)指针有空指针;引用没有空引用
(4)赋值:指针之间的相互赋值会改变指向关系;引用之间的相互赋值,是指向他们指向的对象之间的赋值。
int x = 100, y = 20;
int *p1 = &x, *p2 = &y;
p1 = p2; // p1=&y, p1和p2都指向y
int &r1 = x, &r2 = y;
r1 = r2; // x = y, r1仍是x的引用
(三)类与对象的需要注意的细节:
(1)类的定义以分号结束。
(2)在类的定义中不能对数据成员进行初始化。
(3)类的任何成员都必须指定访问属性,数据成员(private/protected),将成员函数(public)。
(4)类的成员可以是其他类的对象,称为类的组合。但不能以类自身的对象作为本类的成员。
(5) 私有静态成员函数不能在类外部或用对象访问。
(6)静态成员函数中是没有this指针的。
(7)静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
(8)友元一般不使用,破坏了封装性(重载<<和>>运算符时使用)。
(9)对于常数据成员,构造函数就只能通过初始化列表对该数据成员进行初始化且在实例化被初始化后,其值不能改变。
(10)C++不允许直接或间接更改常对象的数据成员,定义常对象时必须进行初始化,而且不能被更新。
(四)运算符重载需要注意的细节:
(1)赋值运算符只能重载为成员函数。
(2)[] 和 () 只能用成员函数重载,不能用友元函数重载。
(3) << 和 >> 只能被重载成友元函数。
四,学习感受
这六周的c++学习,给我最深的感受是难,也意识到自己的水平和能力的的确确还差的很远。每次老师布置的作业,我总是会来来回回折腾好久,但是作业得分都一般般。有时候有些学习内容要消化好久,学习效率也不怎么高,对比有些优秀的同学,也很羡慕,有时候也会有些消极的自我否定的情绪,但前段时间看到马原里的一句话——一切发展都是事物内部矛盾的自我否定,即否定之否定。
这句话从某种程度上让我转变了思维方向,或许现阶段知道自己还有很多的弱项和缺点不是什么坏事,有了这些否定,会更多地反省自己,也更有利于做出积极的改变,才能让自己有所发展和进步。
首先,对于自己学习方法和效率,应该做出相应的调整。我自己有时候容易露怯,有一定畏难心理,总会先挑相对简单的事去做,以后应该先做对自己来说更困难和更麻烦的事,这样其他的事情就不会给自己带来困扰,而且解决难度大的任务往往会花费比自己预期多得多的时间,早做更稳妥。其次,加强自己对时间的规划。反思下自己的学习状态,有时候感觉好像在学,但会浪费大量不必要的时间,自己自控力还是有待提高。以后需要写一些“未完成任务的清单”,这样懈怠的时候,一方面可以提醒自己我还有哪些事情没做,另一方面可以提高效率,让自己做事更紧凑。再其次,要加强实践,学完知识要将理论转化成实践,运用到现实中才能加强记忆和理解。
老师的严格要求,有利于自己多学点东西,希望自己可以在还算年轻的时候多走点上坡路。