C++primer总结

目录

第一章数据处理...2

整形...2

第二章复合类型...3

数组...3

字符串...4

枚举...5

指针...5

第三章函数的使用...6

内联函数...6

默认参数...6

函数的重载...7

函数的模板...7

第四章内存模型和名称空间...7

文件的单独存放...7

变量的链接性...7

函数的链接性...8

语言的链接性...10

动态开辟...10

命名空间...10

命名空间的运用实例...12

第五章类的使用...13

规范写类...13

第六章类和动态内存分配...15

类中的静态成员...15

构造1,构造2,析构2,析构2.17

隐式成员函数...17

new创建的用delete,但是new []创建的用delete []18

静态成员函数由于只是和类相关,所以也只能调用静态成员变量。...18

第七章类的继承...21

默认参数...21

第八章重用代码...22

多重继承...22

模板的使用...24

第九章友元异常和其他...27

友元类...27

第十章string类和标准模板库...28

string类...28

智能指针...28

联合容器...30

第十一章输入输出和文件...31

第一章数据处理

整形

整形:short(16)、int(16-32)、 long(32) 头文件limits包含范围

#include

usingnamespacestd;

voidmain()

{

intint_max =INT16_MAX;

shortshort_max =SHRT_MAX;

longlong_max =LLONG_MAX;

cout<<sizeofshort_max<<"\t"<<sizeof(int)<<"\t"<<sizeoflong_max<<endl;

}

数据可以大一点就使用unsigned long long

C++用三种基数来表示整数,10,8,16,当然也可以在数字后面加上LU来说明是long和unsigned

#include

/*

* they are same

*/

usingnamespacestd;

voidmain()

{

int ten = 42;

inteight = 052;

intsixteen = 0x2A;

cout<<ten<<"\t"<<eight<<"\t"<<sixteen<<endl;

}

字符型

字符型char

Unsigned char 和signedchar 可以让char的值从0-255

Float32位 double64 记数可以使用科学计数法3.2E2=320

第二章复合类型

数组

字符串以’\0’结尾,是字符串类型就发生了取得内存地址的条件,此外char str[6];中

Str=&str[0];所以不可以字符串之间赋值

#include

//#include

/*

*字符串赋值的方法有两种(常用),直接赋值,从键盘输入

*在数组中 str[6], str=&str[0];

*/

usingnamespacestd;

voidmain()

{

charstr1[6] = {'h','e','l','l','o'};// it is char array

charstr2[6] = {'h','e','l','l','o','\0'};//it is string

charstr3[6] ="hello";//autoto add \0,it is string

charstr4[] ="hello";//it isstring

cout<<"hello""everyone"<<endl;//allow to jointstring

}

#include

//#include

/*

* char[]以/0结尾,所以在键盘进行输入时有了空格,则以为结束,可以使用cin.getline(city,len),cin.get(city,len)输入。

*getline()是达到len长度时候结束,或者遇到换行的时候结束。但是get()遇到换行结束,但是可接受换行。

*

*/

usingnamespacestd;

voidmain()

{

charcity[20];

charname[20];

//cin.getline(city,20);cin.getline(name,20);与下一行等效

cin.get(city,20); cin.get(); cin.get(name, 20);

cout<<name<<"\t"<<city<<endl;

}

#include

//#include

/*strcpy(str1,str2) strcat(str1,str2)

* char[]以/0结尾,所以在键盘进行输入时有了空格,则以为结束,可以使用cin.getline(city,len),cin.get(city,len)输入。

*getline()是达到len长度时候结束,或者遇到换行的时候结束。但是get()遇到换行结束,但是可接受换行。

*

*/

usingnamespacestd;

voidmain()

{

charcity[20];

charname[20];

//cin.getline(city,20);cin.getline(name,20);与下一行等效

cin.get(city,20); cin.get(); cin.get(name, 20);

cout<<name<<"\t"<<city<<endl;

}

字符串

#include

#include

/*

*字符串相当于字符数组,可以和字符数组一样使用

*字符串可以直接赋值,相加,拼接,可以直接cin和cout

*/

usingnamespacestd;

voidmain()

{

stringstr1 ="nihao";

if(str1[5]=='\0') { cout<<"hello everyone\n"; }

stringstr2 = str1+" zxw\n";

cout<<str2<<str2.length()<<"\t"<<str2.size();

}

结构体和共用体的使用

结构体是可以定义多个数据类型,但是共用体是每次只能储存一个值

#include

#include

/*

*/

usingnamespacestd;

structmystruct

{

stringname;

intstudentno;

charsex;

boolgood : 1;

unionid

{

floatsalary;

stringcareer;

}x;

}my1;

voidmain()

{

my1.x.salary= 100;

}

枚举

只是定义了赋值操作,没有运算操作,当然,赋值附很大的时候将会发出警告,按照原则,应该有多少赋值多少

#include

#include

/*

*/

usingnamespacestd;

voidmain()

{

enummy{ONE=1,TWO=2,THREE};

cout<<THREE<<endl;

}

指针

在c++创建的时候,计算机分配用来储存地址的内存,并不会去储存值,所以为数据提供空间是一个独立的步骤。指针的加减是以所在的类型为单位个数进行加减。*(a+1)=a[1];

创建动态数组:

#include

#include

/*

当内存耗尽时候new将会返回0,delete释放内存,并不会删除指针

*/

usingnamespacestd;

voidmain()

{

int* p_int =newint;

*p_int= 1024;

deletep_int;

//delete p_int;不能再次调用释放内存的delete,会发生我发预料的事情

float* P_float;

floatft = 2.1;

P_float= &ft;

//delete P_float;不能释放栈里面的内存,只能释放堆得

}

C++对数据有三种处理的方式自动存储,随着函数产生随着函数消亡,静态存储,生命周期可能是整个程序的生命周期,动态存储由程序员控制。

第三章函数的使用

内联函数:example:

inlinevoidSwap(floata,floatb)

{

a=a+b;

b=a-b;

a=a-b;

}

不能递归调用,原理是,所有的代码翻译成机器代码进行解读,正常的函数调用需要机器跳到指定的位置,但是内联函数就不需要了,把代码镶嵌在内部,但是后果是占用的内存较多。

引用变量:

引用的变量建立就直接赋值;

传递参数的三种方式:值传递,指针传递和引用传递,引用实质上是内存中同一个地址的别名,对于引用,会发生值的改变,除非将值设置成const的引用的类型。小的值传递通常使用值传递,大一点的比如结构体这些使用指针,对象则使用引用传递,仅是建议。

默认参数

默认参数从右往左开始赋值,这样的方式仅仅是提供了一种便捷的操作方式而已。

voidSwap(floata,floatb=9)

{

a=a+b;

b=a-b;

a=a-b;

}

函数的重载

参数的数目和类型的不相同可以重载函数,建议少用。

函数的模板

template<classany>voidSwap(any&q1,any&q2);//定义模板函数,在调用的时候叫做模板的实例化

templatevoidSwap<int>(int&q1,int&q2);//模板显示具体化

第四章内存模型和名称空间

文件的单独存放

一般可以分为三种文件:头文件(负责各种声明和全局变量或者define的定义等),结构文件(为头文件的函数等定义的文件),调用文件(包含main的文件)

头文件的包含一般使用“”,使用<>会从标准库里面先去寻找。

储存的持续性,作用域和链接性:

自动储存持续性:在函数内部定义的局部变量(作用域是由一个花括号括起来的东西)

静态存储持续性:在函数外部定义或者static定义的变量,作用域由全局和局部。

动态存储持续性:由程序员指定new创建直到delete删除。存活周期结束。

注:在函数内部声明的static 和new 创建的东西虽然存在,但是由于作用域的存在,在别的地方不好引用。

变量的链接性

(在另一个源文件定义)在函数外部定义,则全局变量,链接性为外部,即所有文件可以使用,但是加上extern声明存在之后可以使用。但是变量的定义的时候附加static 或者 const则在本文件可以使用,链接性为内部。

(在头文件里面定义的变量,建议不要再这里面定义)包含头文件,则包含里面的所有定义了,如果不声明为内部链接性,在多个文件使用这个头文件时候,将会发生重复定义错误。不能定义外部链接性的变量。

Example:(三个文件)

#pragmaonce

//mytemp1.h

#ifndefzylg1_

#definezylg1_

template<classany>voidSwap(any&q1,any&q2);//定义模板函数,在调用的时候叫做模板的实例化

templatevoidSwap<int>(int&q1,int&q2);//模板显示具体化

constintb = 8;

staticinta = 6;

#endif// !zylg1_

//metemp1.cpp

#include

#include"mytemp1.h"

std::stringextern1 ="具有外部链接性的变量,可以在全部文件使用,加上extern说明就行";

staticstd::stringstr1 ="声明为静态的具有内部链接性,只可以在本文件使用";

conststd::stringstr2 ="声明为静态的具有内部链接性,只可以在本文件使用";

template<classany>voidSwap(any&q1,any&q2)

{

q1=q1+q2;

q2=q1-q2;

q1=q1-q2;

}

//temp.cpp包含main()文件

#include

#include"mytemp1.h"

#include

usingnamespacestd;

externstringextern1;//使用另外一个源文件定义的

voidmain()

{

extern1="这是重新使用外部变量";

inta1 = 2, a2 = 4;

Swap(a1,a2);

cout<<a1<<a2<<endl;

cout<<extern1<<b<<endl;

}

函数的链接性

(在另一个源文件)同样的如果不添加static或者const的函数,则是外部链接性的。但是内部链接性声明之后,那就意味着在别的源文件里面重新定义函数不会发生重复定义的错误。

//metemp1.cpp

#include

voidSwap(int&a,int&b)

{

a=a+b;

b=a-b;

a=a-b;

}

//temp.cpp包含main()文件

#include

#include

usingnamespacestd;

externvoidSwap(int&q1,int&q2);

voidmain()

{

inta1 = 2, a2 = 4;

Swap(a1,a2);

cout<<a1<<a2<<endl;

}

//metemp1.cpp

#include

staticvoidSwap(int&a,int&b)

{

a=a+b;

b=a-b;

a=a-b;

}

//temp.cpp包含main()文件

#include

#include

usingnamespacestd;

voidSwap(int&q1,int&q2)

{

q1=q1+q2;

q2=q1-q2;

q1=q1-q2;

}

voidmain()

{

inta1 = 2, a2 = 4;

Swap(a1,a2);

cout<<a1<<a2<<endl;

}

注:extern只是让阅读代码的人知道外部存在这东西,并没无多大作用,可省略,但不建议。这也就是头文件的由来,可以看成是全部的外部的成员集合在一起,但是省略了extern。

语言的链接性

由于c和c++编译器处理的效果不一样,

//temp.cpp包含main()文件

#include

#include

usingnamespacestd;

extern"C++"voidSwap(int&q1,int&q2);

voidmain()

{

inta1 = 2, a2 = 4;

Swap(a1,a2);

cout<<a1<<a2<<endl;

}

动态开辟

C++的内存分成三个部分静态变量,自动变量,和动态储存部分,new负责在heap里面找到合适的内存。New的用法

//temp.cpp包含main()文件

#include

#include

usingnamespacestd;

structstudent

{

charname[20];

intnum;

};

voidmain()

{

charch1[30], ch2[30];

studentst1, st2;

intnum1, num2;

st1=newstudent;//place create in heap

st2=new(ch1)student;//place create in ch1

num1=newint;//place create in heap

num2=new(ch2)int;//create in ch2

cout<<st1<<"\t"<<st2<<"\t"<<&ch1<<endl;

cout<<num1<<"\t"<<num2<<"\t"<<&ch2<<endl;

}

命名空间

//temp.cpp包含main()文件

#include

#include

/*

*不允许在函数内部命名名称空间

*名称空间可以嵌套

*当名称空间的名称省略的时候就相当于具有内部链接性的静态全局变量。是一种好的替代方式。

*名称空间的using声明(使用单个)和using 编译(使用全部)

*/

namespacemyspace

{

usingstd::string;//using声明

usingstd::cout;

usingstd::cin;

stringname;

intnum;

voidshow()

{

cout<<name<<"\t"<<num<<std::endl;

}

voidinput()

{

cin>>name>>num;

show();

}

}

namespacemyspace//和上一个空间是同一个空间,未写完继续写

{

stringstr ="你好啊,我在myspace空间里面";

namespacemyspaceson//可以进行嵌套,命名空间就相当于一个作用域。

{

stringstr ="hello every one";

}

}

namespacemy =myspace;//别名

voidmain()

{

usingnamespacemyspace;//using编译

input();

cout<<myspaceson::str<<std::endl;

}

命名空间的运用实例

#pragmaonce

//mytemp1.h

#ifndefzylg1_

#definezylg1_

namespacemyspace1

{

namespace//==static or constdefine

{

intnumber = 30;

}

voidSwap(int&a,int&b);

}

namespacemyspace2

{

voidShow(inta,intb);

}

#endif// !zylg1_

//metemp1.cpp

#include

#include"mytemp1.h"

namespacemyspace1

{

voidSwap(int&a,int&b)

{

a=a+b;b=a-b;a=a-b;

}

}

namespacemyspace2

{

usingnamespacestd;

voidShow(inta,intb)

{

cout<<"a="<<a<<"\t b="<<b<<endl;

}

}

//temp.cpp包含main()文件

#include

#include"mytemp1.h"

voidmain()

{

inta=2,b=4;

usingnamespacemyspace1;//using编译

Swap(a,b);

myspace2::Show(a,b);

}

第五章类的使用

规范写类

#pragmaonce

//mytemp1.h

#ifndefzylg1_

#definezylg1_

namespacemyspace1

{

classTime

{

private:

inthours, minutes;

public:

Time(int,int);

Time();

voidaddMin(intm);

voidaddHor(inth);

voidReset();

Timeoperator+(constTime&t)const;

voidShow()const;//对于不修改里面的值得函数,应该在后面加上const,防止数据修改

friendvoiddisplay(constTime&t);

friendstd::ostream&operator<<(std::ostream&os,constTime&t);

};

}

#endif// !zylg1_

//metemp1.cpp

#include

#include"mytemp1.h"

namespacemyspace1

{

namespace

{

usingstd::cout;

usingstd::endl;

}

Time::Time()

{

}

Time::Time(inth=0,intm=0)

{

if(m>= 60)

{

hours=m/ 60+h;

minutes=m% 60;

}

else

{

hours=h;

minutes=m;

}

}

voidTime::addMin(intm)

{

hours+= (m+ minutes) / 60;

minutes= (m+ minutes) % 60;

}

voidTime::addHor(inth)

{

hours+=h;

}

voidTime::Reset()

{

hours= minutes = 0;

}

TimeTime::operator+(constTime&t)const

{

returnTime(hours +t.hours, minutes +t.minutes);

}

voidTime::Show()const

{

cout<<hours<<":"<<minutes<<endl;

}

voiddisplay(constTime&t)

{

cout<<t.hours<<":"<<t.minutes<<endl;

}

std::ostream&operator<<(std::ostream&os,constTime&t)

{

cout<<t.hours<<":"<<t.minutes<<endl;

returnos;

}

}

//temp.cpp包含main()文件

#include

#include"mytemp1.h"

/*

*规范的格式,在头文件不许出现外部链接性的全局变量,在源文件尽量不出现,此外命名空间用起来,好了万事大吉

*/

voidmain()

{

usingmyspace1::Time;

Timet1(1,31),t2(2,30),t3,t4;

t3=t1+t2;

t1.Show();

t2.Show();

t3.Show();

t4=t1+t2+t3;//t1.operator+(t2.operator+(t3))

t4.Show();

display(t4);//it is friendfuntion

}

Cout<<返回的时ostream的对象,所以可以继续<<

第六章类和动态内存分配

:(类的声明只是描述内存的分配,但是不会分配内存)

类中的静态成员不能够直接初始化,其余可以,但是const int/枚举 类型的静态成员可以初始化。静态成员赋值那就意味该静态变在内存中存在,那就得分配内存(类的声明只是描述内存的分配),所以如例题中:在类中定义staticcintnum_strings ;

然后初始化 intStringBad::num_strings = 3;这就相当于申请了一个int大小的内存去储存静态变量。

classStringBad

{

private:

char* str="shixsa";//可以赋值,但是意义不大。

intlen=3;

public:

//static const std::stringnum_strings="hello";//can`t not to initialize

staticconstintnum_strings = 2;//can initialize

public:

StringBad(constchar*s);

StringBad();

~StringBad();

friendstd::ostream&operator<<(std::ostream&os,constStringBad&st);

}

静态变量的使用

#pragmaonce

//mytemp1.h

#ifndefzylg1_

#definezylg1_

namespacemyspace

{

namespace

{

usingstd::cout;

usingstd::cin;

usingstd::endl;

}

classStringBad

{

private:

char* str="shixsa";

intlen=3;

public:

staticintnum_strings;

voiddisplay();

StringBad(constchar*s);

StringBad();

//~StringBad();

friendstd::ostream&operator<<(std::ostream&os,constStringBad&st);

};

}

#endif// !zylg1_

//metemp1.cpp

#include

#include"mytemp1.h"

namespacemyspace

{

intStringBad::num_strings = 3;

voidStringBad::display()

{

cout<<StringBad::num_strings<<endl;

}

StringBad::StringBad()

{

StringBad::num_strings++;

}

}

//temp.cpp包含main()文件

#include

#include"mytemp1.h"

voidmain()

{

usingmyspace::StringBad;

StringBadst;

st.display();

StringBadst1;

st1.display();

StringBadst2;

st2.display();

StringBadst3;

st3.display();

}

构造1,构造2,析构2,析构2

隐式成员函数

1) 默认构造函数 classname::classname(){}

2) 复制构造函数 classname::classname(const classname& cla){}

StringBadst;

StringBadst1(st);

StringBadst2=StringBad(st);

StringBadst3=st;

StringBad* st4 =newStringBad(st);

在赋值进行操作时,出现指针或者其他因素时最好显示定义,不然两个指针指向同一地址,一旦释放,就不好了

3) 赋值操作符=

4) 默认析构函数classname::~classname()

5) 地址操作符&

new创建的用delete,但是new []创建的用delete []

静态成员函数由于只是和类相关,所以也只能调用静态成员变量。

//zylgstring.h

#pragmaonce

#include

#ifndefZYLG_STRING

#defineZYLG_STRING

usingstd::cin;

usingstd::cout;

usingstd::ostream;

usingstd::istream;

namespaceZYLGSPACE

{

classString

{

private:

char*str;

intlen;

staticintnum_strings;

staticconstintCINLIMIT = 100;

public:

//constrators and other methods

String(constString&s);//复制构造函数

String();

String(constchar*s);

~String();//析构函数

intlength()const{returnlen; }

//overloaded operator methods,()=[]->这四个符号只能在类的成员函数里面进行重载

String&operator=(constString&s);

String&operator=(constchar*s);

char&operator[](inti);

constchar&operator[](inti)const;

//friend function

friendbooloperator>(constString&s1,constString&s2);

friendbooloperator<(constString&s1,constString&s2);

friendbooloperator==(constString&s1,constString&s2);

friendstd::ostream&operator<<(std::ostream&os,constString&s);

friendstd::istream&operator>>(std::istream&is,String&s);

//static function

staticintHowMany();

};

}

#endif// !ZYLG_STRING

//zylgstring.cpp

#include

#include"zylgstring.h"

#pragmawarning(disable:4996)

namespaceZYLGSPACE

{

intString::num_strings = 0;

intString::HowMany()

{

returnnum_strings;

}

String::String(constchar*s)

{

len= std:: strlen(s);

str=newchar[len + 1];

//std::strcpy(str, s);

num_strings++;

}

String::String()

{

len= 4;

str=newchar[1];

str[0]='\0';

num_strings++;

}

String::String(constString&s)

{

num_strings++;

len=s.len;

str=newchar[len + 1];

//std::strcpy(str, s.str);

}

String::~String()

{

--num_strings;

delete[]str;

}

String&String::operator=(constString&st)

{

if(this== &st) {return*this; }

delete[]str;

len=st.len;

str=newchar(len + 1);

//std::strcpy(str, st.str);

return*this;

}

String&String::operator=(constchar*s)

{

delete[]str;

len= std::strlen(s);

str=newchar(len + 1);

std::strcpy(str,s);

return*this;

}

char&String::operator[](inti)

{

returnstr[i];

}

constchar&String::operator[](inti)const

{

returnstr[i];

}

booloperator<(constString&s1,constString&s2)

{

return(std::strcmp(s1.str,s2.str)<0);

}

booloperator==(constString&s1,constString&s2)

{

return(std::strcmp(s1.str,s2.str)==0);

}

booloperator>(constString&s1,constString&s2)

{

returns2.str <s1.str;

}

ostream&operator<<(ostream&os,constString&st)

{

os<<st.str;

returnos;

}

istream&operator >>(std::istream&is,String&s)

{

chartemp[String::CINLIMIT];

is.get(temp,String::CINLIMIT);

if(is)

{

s=temp;

}

while(is&&is.get() !='\n')

{

continue;

}

returnis;

}

}

第七章类的继承

默认参数构成的构造函数,在全部是默认参数时,直接定义对象就行,不用加括号,如下

tabletennisplayer(constcharfirst="none",constcharlast="none",boolhas=false);//exist default

tabletennisplayer::tabletennisplayer(constcharfirst,constcharlast,boolhas){}

tabletennisplayert1("buxnasox"),t2;

成员初始化列表只能用于构造函数,而且:之后的数只能是构造函数或者成员变量,调用时先调用基类的构造函数再调用子类的构造函数。析构函数则是先子类再基类。

2.论继承:继承有公有,私有和保护继承,保护继承是子类能访问,但是其他类不能访问,在基类的成员变量和成员函数如果私有的,那就得通过基类的公有或者保护函数来访问。

子类可以在基类的基础上添加属性,但是不能删除属性。

构造函数,析构函数,友元函数不能继承,当然赋值=也不能继承

3.虚函数的理解:虚函数的存在可以使用动态连编(在运行时选择正确的虚方法的代码),虚函数的实现的方式是,在类中存在虚方法时,类就会自动增加一个一种数组(虚函数表)vtal,里面存放了类对象声明的虚函数的地址。那就形成了每一个函调用时都额外增加了到该表中寻找地址的操作。当然虚函数,也只有成员函数和析构函数可以成为。

Class A;

Class B:publicA

A *a,a1;

B b;

a=&a1;a->display();

a=&b;a->display();

在基类声明display()为虚函数

虚基类是 “虚函数=0;”

第八章重用代码

多重继承

多重继承最好有虚基类,排除二义性,再者就是,进行子类构造的时候,并不能进行虚基类的构造,因为数据不能从子类传递到虚基类的基类。如果一个派生类有多个派生基类,而多个派生基类又有共同基类,则会在该派生类里面保存共同基类的数据成员的多份同名成员。在引用这些同名成员的时候必须加上直接基类的限定符。

classA

{

public:

intn;

voidfun();

};

classB:publicA

{

public:

intdata_b;

};

classC:publicA

{

public:

intdata_c;

};

classD:publicB,publicC

{

public:

intdata_d;

};

Dd1;

d1.B::fun();//正确的使用成员数据的方式

d1.C::fun();

注意:子类只能直接调用直接基类的东西

但是使用虚拟继承,那样只会在D类里面只有一个间接基类的成员,但是由于构造函数不能从子类传递数据到虚拟继承的派生类,所以构造函数必须全部重新构造完全

//temp.cpp包含main()文件

#include

#include"work.h"

classA

{

public:

A(intn):n(n){}

intn;

voidfun();

};

class B :virtual public A

{

public:

B(intn) :A(n) {}

intdata_b;

};

class C :virtual public A

{

public:

C(intn) :A(n) {}

intdata_c;

};

classD:publicB,publicC

{

public:

D(int n) :A(n), B(n), C(n) {}//如果不是虚拟继承将会发生错误

intdata_d;

};

voidmain()

{

//using namespacezylgclassextend;

usingnamespaceWORKSPACE;

Dd1(1);

d1.fun();

}

模板的使用

//stack.h

#pragmaonce

#ifndefSTACK_H_

#defineSTACK_H_

namespaceSTACKSPACE

{

template<classType>

classStack

{

private:

enum{ MAX = 10 };

inttop;

Typeitems[MAX];

public:

Stack();

boolisfull()const;

boolisempty()const;

boolpush(constType&item);

boolpop(Type&item);

};

template<classType>

Stack<Type>::Stack():top(0) {}

template<classType>

boolStack<Type>::isempty()const{returntop == 0; }

template<classType>

boolStack<Type>::isfull()const{return(top+1) == MAX; };

template<classType>

boolStack<Type>::push(constType&item)

{

if(top < MAX)

{

items[top++]=item;

returntrue;

}

elsereturnfalse;

}

template<classType>

boolStack<Type>::pop(Type&item)

{

if(top > 0)

{

item= items[--top];

returntrue;

}

else

{

returnfalse;

}

}

}

#endif// !STACK_H_

template

classclassname

{

public:

voidshow();

};

template

void classname::show() {}

template<classT1,classT2>

classclassname

{

public:

voidshow();

};

templateT1\,class\T2\>

voidclassname<T1,T2>::show() {}

可以在模板里面加入模板,也可以模板函数当然有内部类的说法,可以定义内部类,类定义得简单一些就使用内部类吧。

内部类

内部类与外部类的关系

内部类和外部类是什么关系了,事实上他们什么关系也不是,既不是朋友,也不是父子关系,外部类对内部类没有特权, 内部类对外部类也没有特权, 他们的关系,跟内部类定义在外部类外面一样。

内部类的使用方法

如果要在调用内部类函数,可以主要使用:

[cpp] view plain copy

  1. A::InClass a;

  2. a.funcB();

内部类的作用

1)内部类主要是为了避免命名冲突;(内部类定义为public)

2)为了隐藏名称(内部类定义为private/protected)

classA

{

classB

{

public:

voiddisplay() {std::cout<<"你好\n"; }

};

Bb1;

public:

voidshow() {b1.display(); std::cout<<"hello\n"; }

};

内部模板的使用

template<classT1,classT2>

classclassname

{

public:

template<classU>

classinnerclass//内部模板

{

Uu1;

public:

voiddisplay(Uu1,T1t);

};

innerclass<int> in1;

template<classY>//模板函数

voidprin(Ystr);

voidshow();

};

template<classT1,classT2>

voidclassname<T1,T2>::show() {}

template<classT1,classT2>

template<classU>

voidclassname<T1,T2>::innerclass<U>::display(Uu1,T1t) { cout <<u1+t<< endl; }

template<classT1,classT2>

template<classY>

voidclassname<T1,T2>::prin(Ystr) { cout <<str<< endl; }

使用template主要是让T1等有定义出来,其余就和内部类一样。模板就和正常的数据一样,那自然也可以template<template<classTT>classth,classT1,classT2>classth2{};

当然友元函数也可以friendvoidshow(T1,T2);//类里面声明

template<classT1,classT2>//类外定义

voidshow(T1t1,T2t2) { cout <<t1+t2<< endl; }

template起到传递类型的作用

第九章友元异常和其他

友元类

当定义为友元类时候,友元类可以访问此类的私有成员,定义友元类不用说明其存在

classA

{

public:

friendclassB;

};

classB

{

};

但是竟可能不要定义友元类,可以通过友元函数去处理问题。

异常:

Abort()和exit()的区别是,exit()会刷新文件缓冲区,但是不会回显消息。

Void fun()throw(数据类型);

Try

{

fun();

}

Catch(数据类型 e)

{

//处理程序

}

异常处理的原理是,首先会让异常的地方throw,然后try{}块结束释放内存,当然throw的数据是异常数据的重新的备份,它在发现异常的时候,将抛出的数据进行了复制,然后抛出这个数据。Catch块对应数据类型捕捉异常,之后进行异常的处理。这就是堆栈饥解退。

一般的函数调用是这样的,比如a调用b,那b函数就会在堆栈的顶端,同时顶端的栈堆将会为从a传递进来的参数和b自己创建的变量以及返回地址分配内存。如果b再调用c也是如此,在b调用完成的时候,堆栈将会释放内存,根据返回地址找到a的位置,继续执行下面的语句。

异常处理的基类应该放在最后一个catch里面,因为放在前面将会捕捉派生的对象。

如果不知道catch的对象类型,可以使用…代替

RTTI(运行阶段类型识别)只是适用于包含虚函数的类,因为也只有虚函数才去区分谁是谁

dynamic_cast安全转换对象

tabletennisplayer* t1=newtabletennisplayer();

rateplayer*r1 =newrateplayer("hello","hello",false,2);

t1 =dynamic_cast<tabletennisplayer*>(r1);//安全转换,失败返回空指针

t1->name();

ciwai

const_cast()把const对象类型的数据变成普通的,地址一样,然后可以进行修改

staic_cast/reinterpre_cast

typeid()可以知道对象的所属类型

if(typeid(rateplayer)==typeid(t1)) { cout<<"\nthey are same\n"; cout<<typeid(t1).name()<<endl<<typeid(*t1).hash_code()<<endl; }

第十章string类和标准模板库

string类:

不解释

智能指针

Auto_ptr必须显示的构造,还有就是智能是定义单个变量不能使数组,因为delete而不是delete[],会有让权操作,也就是第一个指针的内容赋值给下一个时,第一个失效。注意:智能指针是自动调用delete,也就是堆栈里面的元素,所以不能把自变量的地址赋给智能指针。

auto_ptr<int> i1(newint);//必须显示的构造,而且不能使数组,因为数组使用delete[]来释放内存。

int *ptr = new int(3);

i1= auto_ptr<int>(ptr);

cout<< i1 << endl;

STL:

序列式容器vector有超尾指针end,有begin,size(),pop_back(),push_back(),erase(),insert()

vector<int>::iteratorint_iterator;

i1.push_back(3);//在vectror后面添加元素

i1.push_back(2);

i1.push_back(1);

i1.pop_back();

int_iterator= i1.begin();

cout<<"元素的数量:"<< i1.size()<<"\n"<<"现在可以容纳的数量:"<<i1.capacity()<< endl;

cout<<"vector :\n";

while(int_iterator !=i1.end())

{

cout<<*int_iterator<<endl;

int_iterator++;

}

cout<<*(--int_iterator)<<endl;

i1.erase(i1.begin(),i1.begin() + 2);//erase清除前面两个元素

cout<<"erase result:\n";

int_iterator= i1.begin();

while(int_iterator !=i1.end())

{

cout<<*int_iterator<<endl;

int_iterator++;

}

vector<int> int_temp = {1,3,2,4,5 };

cout<<"have insert :\n";

i1.insert(i1.begin(),int_temp.begin(),int_temp.end());//insert()插入元素

for(int_iterator =i1.begin(); int_iterator != i1.end(); int_iterator++) { cout<<*int_iterator<<endl; }

当然可以接受stl的算法,比如for_each(),random_shuffle(),sort()

cout<<"for_each():\n";

std::for_each(int_temp.begin(),int_temp.end(), display);//循环传递元素给作为函数参数

cout<<"random_shuffle();\n";

std::random_shuffle(int_temp.begin(),int_temp.end());//打乱顺序

std::for_each(int_temp.begin(),int_temp.end(), display);

cout<<"sort()\n";

std::sort(int_temp.begin(),int_temp.end());

std::for_each(int_temp.begin(),int_temp.end(), display);

std::random_shuffle(int_temp.begin(),int_temp.end());

cout<<"重新排序\n";

std::sort(int_temp.begin(),int_temp.end(), compa);//进行排序

std::for_each(int_temp.begin(),int_temp.end(), display);

voiddisplay(inta) { cout<<a<<endl; }

boolcompa(int&a,int&b) {returna>b?true:false; }

sort里面既然接受地址那样,那下面也成立

cout<<"对数组进行的操作\n";

intarra[5] = {1,9,0,1,3 };//stl算法对数组进行操作

std::sort(arra,arra + 5,compa);

迭代器(广义上来讲是一种指针):

输入,输出,正向,双向,随机迭代器

Copy()传达的时赋值的操作

std::ostream_iterator<int,char> out(cout,"\n");

std::copy(arra,arra + 5, int_temp.begin());

std::copy(int_temp.begin(),int_temp.end(), out);

cout<<"元素反置\n";

std::copy(int_temp.rbegin(),int_temp.rend(), out);

cout<<"向后插入元素\n";

copy(arra,arra + 3, std::back_insert_iterator<vector<int>>(int_temp));

copy(int_temp.begin(),int_temp.end(), out);

cout<<"向前抽入元素"<<endl;

copy(arra,arra + 3, std::insert_iterator<vector<int>>(int_temp,int_temp.begin()));

copy(int_temp.begin(),int_temp.end(), out);

联合容器

Set和muitimap等,set的操作set_union(),set_intersection(),set_diffrence()

std::set<int> A(arra,arra+5);//set

cout<<"A is\n";

std::copy(A.begin(),A.end(), out);

std::set<int>B;

B.insert(9);

B.insert(2);

cout<<"B is \n";

std::copy(B.begin(),B.end(), out);

std::set<int>C;

cout<<"set_union()\n";

std::set_union(A.begin(),A.end(), B.begin(), B.end(), std::insert_iterator<std::set<int>>(C, C.begin()));

//std::copy(C.begin(), C.end(), out);

std::set_union(A.begin(),A.end(), B.begin(), B.end(), out);

typedefstd::pair<int, std::string>Pair;

std::multimap<int, std::string>mapcode;

mapcode.insert(Pair(1,"hello"));

mapcode.insert(Pair(2,"everyone"));

*out++=mapcode.size();

cout<<endl;

std::pair<std::multimap<int, std::string>::iterator, std::multimap<int, std::string>::iterator> range;

range=mapcode.equal_range(1);

for(std::multimap<int, std::string>::iteratorit = range.first;it!=range.second;++it) { cout<<(*it).second<<endl; }

第十一章输入输出和文件

输入流和输出流:ios_base->ios->各种流

缓冲区为了更有效率的输出数据,先把数据囤积起来一起输出

输出的函数有<<,put(单个字符),write(数组的起始地址,数组的位置)

Flush强制刷新缓冲区

另外有格式控制的头文件,width(10),fill(‘#’),setf(ios_base::xxx)

流的状态(eodbit,badbit,failbie,goodbit,eof(),bad(),fail(),rdstate(),clear(),setstate())

文件的操作

注:默认情况下以ios_base::trunc清除文件所有的内容打开文件,这样这个就不能和in连用

基本:ios_base::in/out/ate 读文件/写入文件/在末尾写文件

追加:ios_base::app/trunc

此外可以二进制的形式打开文件

为了写入和读出的方便,用二进制的方式写入和读出来,但是对于有虚函数的对象不适用

自由存储:seekg、seekp()其中的参数有正整数向右移动,负整数向后移动,ios_base::beg/end/cur,检查文件指针的位置tellg/tellp()

//temp.cpp包含main()文件

#include

#include

voidmain()

{

constchar* file ="cxq.txt";

std::ifstreamfin(file);

charch;

if(fin.is_open())

{

while(fin.get(ch))

{

std::cout<<ch;

}

}

fin.close();

std::ofstreamfout(file);

if(!fout.is_open()) {std::cerr<<"Can`t open"<<file<<" file for output.\n"; exit(EXIT_FAILURE); }

charstr[] ="我是专业路过\n";

fout<<str<<std::endl;

fout.close();

fin.clear();//清空输入流

fin.open(file);

while(fin.get(ch))

{

std::cout<<ch;

}

fin.close();

}

//temp.cpp包含main()文件

#include

#include

structstudent

{

intnum;

charname[20];

floatscore;

};

voidmain()

{

studentst1{1500730142,"zylg",99.9};

studentst2{ 1500730141,"zzz",1.1 };

char*file ="student.dat";

std::fstreamfin;

intplace = (sizeofst2);

fin.open(file,std::ios_base::out|std::ios_base::in|std::ios_base::app|std::ios_base::binary);

fin.write((char*)&st2,sizeofst2);

fin.seekg(-place,std::ios_base::end);//访问的位置是最后一个结构体的位置

while(fin.read((char*)&st2,sizeofst1))

{

std::cout<<st2.num<<st2.name<<st2.score<<std::endl;

}

fin.close();

}


原文链接: https://www.cnblogs.com/zylg/p/9251768.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/266677

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 下午5:56
下一篇 2023年2月14日 下午5:56

相关推荐