C++ 学习笔记(2)
C++学习笔记(2)
-----------------面向对象编程之继承-------------------
1、定义一个类的时候想重用一个已有的类,就可以使用继承。
classNewClass:publicOldClass{
//新增加的成员
};
新类会继承旧类的全部成员,成为新类中的成员。新类可以增加新的成员,实现对旧类的扩大。继承方式可以有public/private/protected3种,一般使用public方式。旧类成为“父类”或“基类”,新类成为“子类”或“派生类”。不管那种继承方式都是把父类的成员全部继承(复制)到子类中成为子类的成员,其中私有的成员在子类中不能直接访问,公然可以在子类中直接访问。特权是父类中可以用protected来作为成员的访问限制,这类成员称为保护成员。这类成员对外跟私有成员一样,但是在子类中允许直接访问。***尽可能不应protected以避免父子类之间有太强的耦合***。
不同继承方式区分在于继承到子类中以后作为子类的成员对外的访问限制。private方式继承过来后所有成员都成为子类的私有成员,protected方式继承过来以后原来的私有成员还是私有的,原来保护的和公然的都成为子类的保护成员了;一般用public方式继承,继承过来的成员到子类中以后保持原有的访问限制不变。默许是private方式。
继承主要作用是代码重用和对多态提供支持。
创建对象的顺序:构造函数首先调用父类的构造函数,然后依照定义顺序创建成员对象,履行构造函数的函数体。析构跟构造函数相反。构造函数默许调用父类构造函数时不传参数。如果需要传递参数,要在初始化列表中用父类类名来表示。***初始化列表各项排名不分前后,只是指明用甚么初始化谁***
子类定义的函数会隐藏来自父类的同名函数,即便参数表不同也不会构成重载。如果确切需要调用来自父类的那个函数,需要用“类名::”来指明。父子类之间不存在重载。
2、多重继承:一个类可以继承多个类,把所有父类的成员都全部继承过来,可以为每一个父类指定一个继承方式。
继承是一种“是一个”的关系,比如:老师是一个人。
多个父类的构造函数按继承顺序调用,与初始化列表中的顺序无关。析构顺序相反。
3、虚继承:如果希望某一个类被继承到某一级子类中时有了多份要合并只保存一份,这个类在被继承时应当用virtual声明为虚继承,这个类就称为虚基类。
虚继承(钻石继承)中虚基类的构造函数由最底下合并的那个子类的构造函数直接传递参数。
虚基类
/\
子类1子类2
\/
子类
------------------------------------------多态---------------------------------------------------------------
1、什么是多态:对各种对象发出同一种指令时,各个对象能根据本身的情况做出相应的响应。
如果希望在调用函数时系统根据对象的真实类型去转调用相应的函数,需要把那个函数声明为virtual虚函数。子类中可以覆盖这个函数,也自动成为虚函数,覆盖(override)要求函数名和参数表都相同而且返回类型也要一致(比如父类中返回父类指针子类中可以返回子类指针)。
虚函数表:编译器把这个类的全部虚函数的地址都保存在一张表中。每一个这类类的对象里会藏一个指针指向这个虚函数表(在构造函数里做的),对象长度会增加4个字节。
利用多态实现类型辨认:
dynamic_cast子类类型(是父类类型的对象)把看起来是父类类型对象转换成子类类型对象,一般用这个结果来初始化一个子类类型的对象的援用或当场使用。成功则一切顺利,失败则抛出异常终止程序。
dynamic_cast子类*(是父类类型的对象地址)成功则结果为一个正常的子类地址,失败则结果为NULL。常经常使用这一种。
dynamic_cast要求类有虚函数。
typeid关键字实现类型辨认:
#include
typeid(类型或数据)返回一个type_info,type_info里有一个成员name()表示类型的名字,type_info支持==和!=。依赖于编译器。如果累有虚函数,typeid也会利用多态进行类型辨认。
------------------------温习:---------------------------------------------------------------------
classA{
A(intn){}
A(doubled){}
A(constAx){}
};//拷贝构造函数
Aa1(1);Aa2(1.1);Aa3(a1);
voidfunc(Aobj);
func(1);//func(A(1));
func(1.1);//func(A(1.1));
func(a1);//Aobj(a1);==A(Ax)==Ax(a1)
--------------------------------------------------------------------------------------------------------
2、纯虚函数:没有必要或不应当有函数体的虚函数,用“=0;”来取代函数体。有纯虚函数的类称为抽象类(缺少函数体),不允许直接用抽象类创建对象抽象类总是用来作为父类,由子类来实现(覆盖)那些纯虚函数,从而可以创建子类类型的对象,可以当做父类对象来援用,或可以用父类指针指向子类对象。
***使用多态时必须通过父类指针或援用来访问子类对象,而不能重建一个父类对象***
多态也称为动态绑定、晚绑定、运行时绑定。统一接口,便于替换和保护。
3、通过父类指针动态释放子类对象时,默许调用父类的析构。如果希望使用多态调用对象所属的子类的析构函数,应当在父类中把析构函数也声明为虚函数。(可否为纯虚函数?构造可否为虚函数?)
4、string类:C++风格的字符串类,string
构造函数:string(conststrings),string(constchar*s),string(intn,charc)。
运算符:,,=,+,+=,[],at(int),比较运算符,=,=,,==,!=
长度:size(),length(),boolempty(),resize(newsize,fillc)
转换成C风格:c_str(),data()不保证‘\0’,copy(char*to,int字符数,intstart=0)复制从start位置开始的n个字符到to所指向的地方。
字串:substr(intstart,intn)返回从start开始的n个字符组成的一个字串string对象,原对象还保持不变。
追加:append(intn,charc)在末尾追加n个字符
查找:find(charc,intstart=0)
find(constchar*s,intstart=0)
find(conststrings,intstart=0)
rfind(...)参数同上,是从反方向查找,其中可以用string::npos表示末尾
find_first_of(字符串s,intstart=0),从start位置开始查找在字符串s中包括字符。find_first_of(“+-*/”)表示在原字符串中找第一个运算符。
find_last_of(...)
find_first_not_of(...)
find_last_not_of(...)
找到返回下标,没有找到返回string::npos。
删除:erase(intstart=0,intn=string::npos)
替换:replace(intstart,intn,新字符串)
replace(intstart,intn,intn2,charc2)
把从start位置开始的n个字符替换成新字符串或n2个c2.
插入:insert(intpos,新字符串)
insert(intpos,intn,charc)
行输入:gets(buf)容易越界,fgets(buf,siezof(buf),stdin)保存了换行符在末尾,scanf("%[^\n]",buf)读到'\n'为止,也容易越界。
strings;getline(cin,s);
3、异常处理:
什么是异常:不常产生,但没法避免。
处理:
返回毛病码
设置errno全局变量
抛出异常
捕获异常:
用try{}把可能发生异常的代码包起来,紧跟其后用若干个(最少一个)catch(类型e){}来捕获指定类型的异常并处理,处理以后程序从最后一个catch块后继续运行。
抛出异常:throw数据;
------------------------------------温习---------------------------------------------------------------------
1、多态(统一用父类援用或指针调用虚函数),虚函数,虚表指针,动态类型辨认(dynamic_cast子类*(父类*),typeid==type_info,#typeid,name(),==,!=),纯虚函数=0;抽象类(不能直接用来创建对象,但可以援用或指向已有的子类对象),虚析构函数(用delete通过父类指针释放子类对象时用)。string类,异常(try{throw...}catch(...){})
----------------------------------------------------------------------------------------------------------------
4、异常
被throw抛出异常数据不受作用范围的限制,直到被捕获被处理为止,因此在捕获时可以通过援用来犯访问异常数据。即便已被处理的异常数据,也可以用一个不带数据的throw重新抛出。
如果抛出的异常没有被捕获处理,系统会调用terminate()函数终止程序。set_terminate(func)可以指定在terminate时自动调用func函数。
异常传递机制:从throw开始离开正常履行流程,在本函数内找有没有包括它的try{}块,如果有,就顺次查找它的catch块直到第一个类型匹配为止进入这个catch块履行处理,以后从最后一个catch块以后继续履行;如果没有包括它的try{}块或没有类型匹配的catch块,异常数据继续传递到上层函数(调用它的那个函数)中重复这个进程,如果直到main函数还没有完成处理,系统就调用terminate终止程序了。
多个catch块如果同时有父类类型和子类类型,应当把子类类型的放在前面,如果有一个是catch(...),它必须放在最后。
异常声明:一个函数可以声明自己可能抛出哪些类型的异常,格式为:
返回类型函数名(参数表)throw(异常类型列表);
intfunc(inta[],intidx)throw(double,int,string);
如果在函数内部抛出了不在列表中的异常,则会引发意外。可以通过set_unexpected(func)来设置遇到意外情况时调用func。没有异常声明表示可能抛出任何类型的异常,空异常列表表示不会抛出异常。
标准异常:exception类,#includeexception
定义子类覆盖父类的虚函数时,异常声明的内容不能超越父类中这个函数的异常声明内容。
标准库中抛出的异常类型都是exception类的子类。
自己定义异常类型一般继承exception类,覆盖constchar*what()constthrow()函数,返回一个字符串,描写产生了甚么异常。
4、I/Oinput/output
标准库中的输入输出对象:
cin:控制台输入consoleinput(标准输入)
cout:控制台输出consoleoutput(标准输出)
cerr:毛病输出,不缓冲,不重定向
clog:跟cerr一样,
类体系:
---istringstream
---istream:cin-----ifstream
ios-----iostream---fstream
---ostream:cout-----ofstream
---ostringstream
输入:
格式化输入:把一系列字符转化成对应格式的数值保存咋变量中。
ws去掉前导的空白字符(空格、制表符、换行符、回车符、换页符、垂直制表符),hex,dec,oct表示用几进制输入;
cinwshexn;//65==0x65==
非格式化输入:保持原来的格式
get(),get(char)从输入流中读取一个字符,空白字符也照样取走。peek()查看但不去走,putback(char)把一个刚取
走的字符送回输入流中(如果送回的不是刚取走的字符,系统不保证成功)。ignore(intn=1,charend=EOF)从输入流中抛弃
n个字符,但如果提早遇到end就停止抛弃//EOF:endoffile
getline(char数组,数组大小)读取一行输入,如果输入超过最大长度,只读去最大长度-1个字符并追加'\0',并设置毛病标志。
处于毛病状态下的IO对象不再履行IO操作,直到clear()清除毛病状态为止。***注意clear只是清除毛病状态,其实不抛弃输入流中
的字符,想抛弃输入流中的字符用ignore。getline(cin,string对象)则不存在超长问题。IO流对象都可以看成一个bool类型的
数据,当处于正常状态时为真,处于毛病状态时为假。
while(cinn){}//输入出错时循环结束(不匹配,Ctrl+D)
getline可以用第三个参数指定读到甚么字符为止。
tline(buf,maxlen,end_char);
getline(cin,stringobject,end_char);
fail(),bad(),eof(),good()表示3种毛病状态和没有出错。
输出:
格式化输出:把内存中的数值用一系列字符表示出来,比如:,在内存中是0x[],输出时转换成“”。cout;
格式控制:setf(flag)/unsetf(flag)设置/取消标志。标志在ios中定义,使用时应当ios::标志。
boolalpha,dec/hex/oct(三选一),left/right/internal(三选一),scientific/fixed(二选一)科学计数法/小数情势,showbase显示进制前缀(0x/0/无)showpoint显示小数点,showpos显示正符号,uppercase在输出十六进制时的x和a-f和科学计数法中的e用大写字母,unibuf每次输出后都刷新缓冲区。skipws输入时跳过空白字符。
一般使用格式控制符取代标志。
width(w)指定下一项输出占多少个字符的位置,如果实际数据超过指定宽度按实际数据宽度输出而不截断,而且宽度只对下一项有效。实际数据短则用空格填充。fill(c)可以指定用其它字符代替填充。precision(n)把小数的精度(有效数字)设置为n,如果同时指定了fixed表示则表示小数点后的位数为n。
classwf{
intw;
charf;
public:
wf(intw,charf):w(w),f(f){}
friendostreamoperator(ostreamo,constwfx){
dth(x.w);
ll(x.f);
returno;
}
};
coutwf(10,'#')非格式化输出:
put(c),flush(stdout)。
---------------------------------------------------------------------------------------------------------
#include
#include
usingnamespacestd;
istreamfunc(istreami)
{
charc;
do
{
ic;
}while(!isdigit(c));//取走非数字字符
tback(c);//退回一个字符
returni;//i就是cin
}
intmain(intargc,char*argv[])
{
intn=-1;
cinfuncn;
cout"n="return0;
}
-------------------------------------------------------------------------------------------------------------
1、I/O
字符串IO:把字符串当做键盘输入或当做屏幕输出。
operator
#includesstream
istringstreamin(conststringstr);
in...
ostringstreamout;
out...
r()获得字符串
通过它们可以再string类型和各种其它支持,的类型直接转换。
文件IO:#includefstream
ifstreamfin文件输入流对象
ofstreamfout文件输出流对象
fstreamfio文件IO对象,输入输出都可以
都是istream/ostream类的子类,cin/cout能做的事情,文件fin/fout都可以做。文件输入/输出流对象需要跟一个文件关联。
方法1:xfstreamfs(文件路径,打开方式标志=默认值)
方法2:xfsreamfs;en(文件路径,打开方式标志=默认值)
二者都会打开文件,成功与否可以通过检测是不是为真来判断,_open()。
标志:ios::in读,ios::out写,ios::app追加,ios::trunc清空,ios::ate一开始在末尾(可以调到其它地方),输入流默许标志in,输出流对象默许标志outtrunc。
读写:,,get()/put(c),getline(),eof()判断是不是遇到了文件末尾(最后一个字节的后面)。
read(char*addr,intbytes)
write(constvoid*addr,intbytes)
在文件和内存之间直接按原始格式(二进制格式)转存数据。
close()关闭文件,释放资源,同时让缓冲区和磁盘文件的内容同步以避免丢失文件内容。
gcount()获得最后一次读取到的字节数。
定位:
seekp/seekg(偏移量)定位到离文件开始制定偏移量的位置,0表示就在开头。seekp/seekg(偏移量,参考基点),基点可以是ios::beg,ios::end,ios::粗人三选一。
C\C++语言程序设计
再多的文字也表达不完我们要学的东西,所以希望需要学习的朋友可以双
击原文链接,直接转入学习群交换,每天晚上8点开始语音解答,每天晚
上九点开始授课;遇到问题可以加我们的学习群;群里面找老司机给你们
解答C/C++JAVA疑问杂题要编译器要离线视频可以加群群文件下载
点击下方“浏览原文”
北京治疗白癜风怎么治如何治疗皮肤白癜风