目录
第一章 数据处理... 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
using namespace std;
void main()
{
int int_max = INT16_MAX;
short short_max = SHRT_MAX;
long long_max = LLONG_MAX;
cout<< sizeof short_max <<"\t"<<sizeof(int)<<"\t"<<sizeof long_max<< endl;
}
数据可以大一点就使用unsigned long long
C++用三种基数来表示整数,10,8,16,当然也可以在数字后面加上LU来说明是long和unsigned
#include
/*
* they are same
*/
using namespace std;
void main()
{
int ten = 42;
int eight = 052;
int sixteen = 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];
*/
using namespace std;
void main()
{
char str1[6] = { 'h','e','l','l','o' };// it is char array
char str2[6] = { 'h','e','l','l','o' ,'\0'};//it is string
char str3[6] = "hello"; //autoto add \0,it is string
char str4[] = "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()遇到换行结束,但是可接受换行。
*
*/
using namespace std;
void main()
{
char city[20];
char name[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()遇到换行结束,但是可接受换行。
*
*/
using namespace std;
void main()
{
char city[20];
char name[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
*/
using namespace std;
void main()
{
string str1 = "nihao";
if (str1[5] =='\0') { cout <<"hello everyone\n"; }
string str2 = str1 + " zxw\n";
cout<< str2<<str2.length()<<"\t"<<str2.size();
}
结构体和共用体的使用
结构体是可以定义多个数据类型,但是共用体是每次只能储存一个值
#include
#include
/*
*/
using namespace std;
struct mystruct
{
string name;
int studentno;
char sex;
bool good : 1;
union id
{
float salary;
string career;
}x;
}my1;
void main()
{
my1.x.salary= 100;
}
枚举:
只是定义了赋值操作,没有运算操作,当然,赋值附很大的时候将会发出警告,按照原则,应该有多少赋值多少
#include
#include
/*
*/
using namespace std;
void main()
{
enum my{ONE=1,TWO=2,THREE};
cout<< THREE << endl;
}
指针:
在c++创建的时候,计算机分配用来储存地址的内存,并不会去储存值,所以为数据提供空间是一个独立的步骤。指针的加减是以所在的类型为单位个数进行加减。*(a+1)=a[1];
创建动态数组:
#include
#include
/*
当内存耗尽时候new将会返回0,delete释放内存,并不会删除指针
*/
using namespace std;
void main()
{
int* p_int = new int;
*p_int= 1024;
delete p_int;
//delete p_int;不能再次调用释放内存的delete,会发生我发预料的事情
float * P_float;
float ft = 2.1;
P_float= &ft;
//delete P_float;不能释放栈里面的内存,只能释放堆得
}
C++对数据有三种处理的方式自动存储,随着函数产生随着函数消亡,静态存储,生命周期可能是整个程序的生命周期,动态存储由程序员控制。
第三章 函数的使用
内联函数:example:
inline void Swap(floata, float b)
{
a = a + b;
b = a - b;
a = a - b;
}
不能递归调用,原理是,所有的代码翻译成机器代码进行解读,正常的函数调用需要机器跳到指定的位置,但是内联函数就不需要了,把代码镶嵌在内部,但是后果是占用的内存较多。
引用变量:
引用的变量建立就直接赋值;
传递参数的三种方式:值传递,指针传递和引用传递,引用实质上是内存中同一个地址的别名,对于引用,会发生值的改变,除非将值设置成const的引用的类型。小的值传递通常使用值传递,大一点的比如结构体这些使用指针,对象则使用引用传递,仅是建议。
默认参数
默认参数从右往左开始赋值,这样的方式仅仅是提供了一种便捷的操作方式而已。
void Swap(floata, float b=9)
{
a = a + b;
b = a - b;
a = a - b;
}
函数的重载:
参数的数目和类型的不相同可以重载函数,建议少用。
函数的模板:
template<classany> void Swap(any &q1,any &q2);//定义模板函数,在调用的时候叫做模板的实例化
template void Swap<int>(int &q1,int &q2);//模板显示具体化
第四章 内存模型和名称空间
文件的单独存放:
一般可以分为三种文件:头文件(负责各种声明和全局变量或者define的定义等),结构文件(为头文件的函数等定义的文件),调用文件(包含main的文件)
头文件的包含一般使用“”,使用<>会从标准库里面先去寻找。
储存的持续性,作用域和链接性:
自动储存持续性:在函数内部定义的局部变量(作用域是由一个花括号括起来的东西)
静态存储持续性:在函数外部定义或者static定义的变量,作用域由全局和局部。
动态存储持续性:由程序员指定new创建直到delete删除。存活周期结束。
注:在函数内部声明的static 和new 创建的东西虽然存在,但是由于作用域的存在,在别的地方不好引用。
变量的链接性:
(在另一个源文件定义)在函数外部定义,则全局变量,链接性为外部,即所有文件可以使用,但是加上extern声明存在之后可以使用。但是变量的定义的时候附加static 或者 const则在本文件可以使用,链接性为内部。
(在头文件里面定义的变量,建议不要再这里面定义)包含头文件,则包含里面的所有定义了,如果不声明为内部链接性,在多个文件使用这个头文件时候,将会发生重复定义错误。不能定义外部链接性的变量。
Example:(三个文件)
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
template<classany> void Swap(any &q1,any &q2);//定义模板函数,在调用的时候叫做模板的实例化
template void Swap<int>(int &q1,int &q2);//模板显示具体化
const int b = 8;
static int a = 6;
#endif // !zylg1_
//metemp1.cpp
#include
#include"mytemp1.h"
std::string extern1 = "具有外部链接性的变量,可以在全部文件使用,加上extern说明就行";
static std::string str1 ="声明为静态的具有内部链接性,只可以在本文件使用";
const std::string str2 ="声明为静态的具有内部链接性,只可以在本文件使用";
template<classany> void Swap(any &q1,any &q2)
{
q1 = q1 + q2;
q2 = q1 - q2;
q1 = q1 - q2;
}
//temp.cpp包含main()文件
#include
#include"mytemp1.h"
#include
using namespace std;
extern string extern1;//使用另外一个源文件定义的
void main()
{
extern1= "这是重新使用外部变量";
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
cout<< extern1<<b<<endl;
}
函数的链接性:
(在另一个源文件)同样的如果不添加static或者const的函数,则是外部链接性的。但是内部链接性声明之后,那就意味着在别的源文件里面重新定义函数不会发生重复定义的错误。
//metemp1.cpp
#include
void Swap(int &a,int &b)
{
a = a + b;
b = a - b;
a = a - b;
}
//temp.cpp包含main()文件
#include
#include
using namespace std;
extern void Swap(int &q1,int &q2);
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
//metemp1.cpp
#include
static void Swap(int &a,int &b)
{
a = a + b;
b = a - b;
a = a - b;
}
//temp.cpp包含main()文件
#include
#include
using namespace std;
void Swap(int &q1,int &q2)
{
q1 = q1 + q2;
q2 = q1 - q2;
q1 = q1 - q2;
}
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
注:extern只是让阅读代码的人知道外部存在这东西,并没无多大作用,可省略,但不建议。这也就是头文件的由来,可以看成是全部的外部的成员集合在一起,但是省略了extern。
语言的链接性:
由于c和c++编译器处理的效果不一样,
//temp.cpp包含main()文件
#include
#include
using namespace std;
extern "C++" void Swap(int &q1,int &q2);
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
动态开辟:
C++的内存分成三个部分静态变量,自动变量,和动态储存部分,new负责在heap里面找到合适的内存。New的用法
//temp.cpp包含main()文件
#include
#include
using namespace std;
struct student
{
char name[20];
int num;
};
void main()
{
char ch1[30], ch2[30];
student *st1, *st2;
int *num1, *num2;
st1= new student;//place create in heap
st2= new (ch1) student;//place create in ch1
num1= new int;//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 编译(使用全部)
*/
namespace myspace
{
using std::string;//using声明
using std::cout;
using std::cin;
string name;
int num;
void show()
{
cout<< name << "\t" << num<<std::endl;
}
void input()
{
cin>> name >> num;
show();
}
}
namespace myspace//和上一个空间是同一个空间,未写完继续写
{
string str = "你好啊,我在myspace空间里面";
namespace myspaceson //可以进行嵌套,命名空间就相当于一个作用域。
{
string str = "hello every one";
}
}
namespace my =myspace;//别名
void main()
{
using namespace myspace;//using 编译
input();
cout<< myspaceson::str << std::endl;
}
命名空间的运用实例
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespacemyspace1
{
namespace//==static or constdefine
{
int number = 30;
}
void Swap(int &a,int &b);
}
namespacemyspace2
{
void Show(inta,int b);
}
#endif // !zylg1_
//metemp1.cpp
#include
#include"mytemp1.h"
namespacemyspace1
{
void Swap(int &a,int &b)
{
a = a + b; b =a - b; a = a - b;
}
}
namespacemyspace2
{
using namespace std;
void Show(inta,int b)
{
cout<< "a=" << a << "\t b=" <<b << endl;
}
}
//temp.cpp包含main()文件
#include
#include "mytemp1.h"
void main()
{
int a=2,b=4;
using namespace myspace1;//using 编译
Swap(a,b);
myspace2::Show(a,b);
}
第五章 类的使用
规范写类
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespacemyspace1
{
class Time
{
private:
int hours, minutes;
public:
Time(int,int);
Time();
void addMin(intm);
void addHor(inth);
void Reset();
Time operator+(const Time& t)const;
void Show()const;//对于不修改里面的值得函数,应该在后面加上const,防止数据修改
friend void display(constTime &t);
friend std::ostream&operator<<(std::ostream &os,const Time &t);
};
}
#endif // !zylg1_
//metemp1.cpp
#include
#include"mytemp1.h"
namespacemyspace1
{
namespace
{
using std::cout;
using std::endl;
}
Time::Time()
{
}
Time::Time(inth=0,int m=0)
{
if (m >= 60)
{
hours= m / 60+h;
minutes= m % 60;
}
else
{
hours= h;
minutes= m;
}
}
void Time::addMin(int m)
{
hours+= (m + minutes) / 60;
minutes= (m + minutes) % 60;
}
void Time::addHor(int h)
{
hours+= h;
}
void Time::Reset()
{
hours= minutes = 0;
}
Time Time::operator+(constTime& t)const
{
return Time(hours + t.hours, minutes + t.minutes);
}
void Time::Show()const
{
cout<< hours << ":" << minutes<< endl;
}
void display(constTime &t)
{
cout<< t.hours << ":"<< t.minutes << endl;
}
std::ostream& operator<<(std::ostream & os, const Time &t)
{
cout<< t.hours << ":"<< t.minutes << endl;
return os;
}
}
//temp.cpp包含main()文件
#include
#include "mytemp1.h"
/*
*规范的格式,在头文件不许出现外部链接性的全局变量,在源文件尽量不出现,此外命名空间用起来,好了万事大吉
*/
void main()
{
using myspace1::Time;
Time t1(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/枚举 类型的静态成员可以初始化。静态成员赋值那就意味该静态变在内存中存在,那就得分配内存(类的声明只是描述内存的分配),所以如例题中:在类中定义staticc int num_strings ;
然后初始化 int StringBad::num_strings = 3;这就相当于申请了一个int大小的内存去储存静态变量。
class StringBad
{
private:
char * str="shixsa";//可以赋值,但是意义不大。
int len=3;
public:
//static const std::stringnum_strings="hello";//can`t not to initialize
static const int num_strings = 2;//can initialize
public:
StringBad(const char *s);
StringBad();
~StringBad();
friend std::ostream &operator<<(std::ostream &os,const StringBad &st);
}
静态变量的使用
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespace myspace
{
namespace
{
using std::cout;
using std::cin;
using std::endl;
}
class StringBad
{
private:
char * str="shixsa";
int len=3;
public:
static int num_strings;
void display();
StringBad(const char *s);
StringBad();
//~StringBad();
friend std::ostream &operator<<(std::ostream &os,const StringBad &st);
};
}
#endif // !zylg1_
//metemp1.cpp
#include
#include"mytemp1.h"
namespace myspace
{
int StringBad::num_strings = 3;
void StringBad::display()
{
cout<< StringBad::num_strings << endl;
}
StringBad::StringBad()
{
StringBad::num_strings++;
}
}
//temp.cpp包含main()文件
#include
#include"mytemp1.h"
void main()
{
using myspace::StringBad;
StringBad st;
st.display();
StringBad st1;
st1.display();
StringBad st2;
st2.display();
StringBad st3;
st3.display();
}
构造1,构造2,析构2,析构2
隐式成员函数
1) 默认构造函数 classname::classname(){}
2) 复制构造函数 classname::classname(const classname& cla){}
StringBad st;
StringBad st1(st);
StringBad st2=StringBad(st);
StringBad st3=st;
StringBad* st4 = new StringBad(st);
在赋值进行操作时,出现指针或者其他因素时最好显示定义,不然两个指针指向同一地址,一旦释放,就不好了
3) 赋值操作符=
4) 默认析构函数classname::~classname()
5) 地址操作符&
new创建的用delete,但是new []创建的用delete []
静态成员函数由于只是和类相关,所以也只能调用静态成员变量。
//zylgstring.h
#pragma once
#include
#ifndefZYLG_STRING
#define ZYLG_STRING
usingstd::cin;
usingstd::cout;
using std::ostream;
using std::istream;
namespaceZYLGSPACE
{
class String
{
private:
char *str;
int len;
static int num_strings;
static const int CINLIMIT = 100;
public:
//constrators and other methods
String(const String &s);//复制构造函数
String();
String(const char *s);
~String();//析构函数
int length()const {return len; }
//overloaded operator methods,()=[]->这四个符号只能在类的成员函数里面进行重载
String & operator=(const String& s);
String & operator=(const char*s);
char & operator[](int i);
const char & operator[](inti)const;
//friend function
friend bool operator>(constString& s1, const String &s2);
friend bool operator<(constString& s1, const String &s2);
friend bool operator==(constString& s1, const String &s2);
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s);
//static function
static int HowMany();
};
}
#endif // !ZYLG_STRING
//zylgstring.cpp
#include
#include"zylgstring.h"
#pragma warning(disable:4996)
namespaceZYLGSPACE
{
int String::num_strings = 0;
int String::HowMany()
{
return num_strings;
}
String::String(constchar* s)
{
len= std:: strlen(s);
str= new char[len + 1];
//std::strcpy(str, s);
num_strings++;
}
String::String()
{
len= 4;
str= new char[1];
str[0]= '\0';
num_strings++;
}
String::String(constString& s)
{
num_strings++;
len= s.len;
str= new char[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= new char(len + 1);
//std::strcpy(str, st.str);
return *this;
}
String & String::operator=(constchar* s)
{
delete[] str;
len= std::strlen(s);
str= new char(len + 1);
std::strcpy(str,s);
return *this;
}
char & String::operator[](inti)
{
return str[i];
}
const char & String::operator[](inti)const
{
return str[i];
}
bool operator<(const String& s1,constString& s2)
{
return (std::strcmp(s1.str,s2.str)<0);
}
bool operator==(const String& s1, constString& s2)
{
return (std::strcmp(s1.str,s2.str)==0);
}
bool operator>(const String& s1, constString& s2)
{
return s2.str < s1.str;
}
ostream & operator<<(ostream & os, const String&st)
{
os << st.str;
return os;
}
istream & operator >> (std::istream & is, String &s)
{
char temp[String::CINLIMIT];
is.get(temp, String::CINLIMIT);
if (is)
{
s = temp;
}
while (is &&is.get() != '\n')
{
continue;
}
return is;
}
}
第七章 类的继承
默认参数构成的构造函数,在全部是默认参数时,直接定义对象就行,不用加括号,如下
tabletennisplayer(const char * first="none",constchar * last="none",bool has=false);//exist default
tabletennisplayer::tabletennisplayer(constchar * first, const char * last ,bool has ){}
tabletennisplayer t1("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;”
第八章 重用代码
多重继承:
多重继承最好有虚基类,排除二义性,再者就是,进行子类构造的时候,并不能进行虚基类的构造,因为数据不能从子类传递到虚基类的基类。如果一个派生类有多个派生基类,而多个派生基类又有共同基类,则会在该派生类里面保存共同基类的数据成员的多份同名成员。在引用这些同名成员的时候必须加上直接基类的限定符。
class A
{
public:
int n;
void fun();
};
class B :public A
{
public:
int data_b;
};
class C :public A
{
public:
int data_c;
};
class D :public B,public C
{
public:
int data_d;
};
D d1;
d1.B::fun();//正确的使用成员数据的方式
d1.C::fun();
注意:子类只能直接调用直接基类的东西
但是使用虚拟继承,那样只会在D类里面只有一个间接基类的成员,但是由于构造函数不能从子类传递数据到虚拟继承的派生类,所以构造函数必须全部重新构造完全
//temp.cpp包含main()文件
#include
#include"work.h"
class A
{
public:
A(int n):n(n){}
int n;
void fun();
};
class B :virtual public A
{
public:
B(int n) :A(n) {}
int data_b;
};
class C :virtual public A
{
public:
C(int n) :A(n) {}
int data_c;
};
class D :public B,public C
{
public:
D(int n) :A(n), B(n), C(n) {}//如果不是虚拟继承将会发生错误
int data_d;
};
void main()
{
//using namespacezylgclassextend;
using namespace WORKSPACE;
D d1(1);
d1.fun();
}
模板的使用:
//stack.h
#pragma once
#ifndefSTACK_H_
#define STACK_H_
namespaceSTACKSPACE
{
template <classType>
class Stack
{
private:
enum { MAX = 10 };
int top;
Type items[MAX];
public:
Stack();
bool isfull()const;
bool isempty()const;
bool push(constType& item);
bool pop(Type &item);
};
template <classType>
Stack<Type>::Stack():top(0) {}
template <classType>
bool Stack<Type>::isempty()const {return top == 0; }
template <classType>
bool Stack <Type>::isfull()const {return (top+1) == MAX; };
template <classType>
bool Stack<Type>::push(constType& item)
{
if (top < MAX)
{
items[top++]= item;
return true;
}
else return false;
}
template <classType>
bool Stack<Type>::pop(Type&item)
{
if (top > 0)
{
item = items[--top];
return true;
}
else
{
return false;
}
}
}
#endif // !STACK_H_
template
classclassname
{
public:
voidshow();
};
template
void classname
template <classT1,class T2>
class classname
{
public:
void show();
};
template
void classname<T1, T2>::show() {}
可以在模板里面加入模板,也可以模板函数,当然有内部类的说法,可以定义内部类,类定义得简单一些就使用内部类吧。
内部类
内部类与外部类的关系
内部类和外部类是什么关系了,事实上他们什么关系也不是,既不是朋友,也不是父子关系,外部类对内部类没有特权, 内部类对外部类也没有特权, 他们的关系,跟内部类定义在外部类外面一样。
内部类的使用方法
如果要在调用内部类函数,可以主要使用:
[cpp] view plain copy
1. A::InClass a;
2. a.funcB();
内部类的作用
1)内部类主要是为了避免命名冲突;(内部类定义为public)
2)为了隐藏名称(内部类定义为private/protected)
class A
{
class B
{
public:
void display() {std::cout<< "你好\n"; }
};
B b1;
public:
void show() {b1.display(); std::cout<< "hello\n"; }
};
内部模板的使用
template <classT1,class T2>
class classname
{
public:
template<classU>
class innerclass//内部模板
{
U u1;
public:
void display(Uu1, T1 t);
};
innerclass<int> in1;
template<classY>//模板函数
void prin(Ystr);
void show();
};
template <classT1,class T2>
void classname<T1, T2>::show() {}
template<classT1,class T2>
template<classU>
void classname<T1, T2>::innerclass<U>::display(Uu1,T1 t) { cout << u1 + t << endl; }
template <classT1,class T2>
template <classY>
void classname<T1, T2>::prin(Y str) { cout <<str << endl; }
使用template主要是让T1等有定义出来,其余就和内部类一样。模板就和正常的数据一样,那自然也可以 template<template<classTT> class th, class T1,class T2> class th2 {};
当然友元函数也可以friend void show(T1,T2);//类里面声明
template <classT1,class T2>//类外定义
void show(T1t1, T2 t2) { cout << t1 + t2 << endl; }
template
第九章 友元异常和其他
友元类:
当定义为友元类时候,友元类可以访问此类的私有成员,定义友元类不用说明其存在
class A
{
public:
friend class B;
};
class B
{
};
但是竟可能不要定义友元类,可以通过友元函数去处理问题。
异常:
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 = new rateplayer("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>::iterator int_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"<< "现在可以容纳的数量:"< 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; } bool compa(int &a,int &b) { return a > b ?true : false; } sort里面既然接受地址那样,那下面也成立 cout << "对数组进行的操作\n"; int arra[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::copy(C.begin(), C.end(), out); std::set_union(A.begin(),A.end(), B.begin(), B.end(), out); typedef std::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 range=mapcode.equal_range(1); for (std::multimap<int, std::string>::iterator it = 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 void main() { const char* file = "cxq.txt"; std::ifstream fin(file); char ch; if (fin.is_open()) { while (fin.get(ch)) { std::cout<< ch; } } fin.close(); std::ofstream fout(file); if (!fout.is_open()) {std::cerr<< "Can`t open"<< file << " file for output.\n"; exit(EXIT_FAILURE); } char str[] = "我是专业路过\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 struct student { int num; char name[20]; float score; }; void main() { student st1{1500730142,"zylg",99.9}; student st2{ 1500730141,"zzz",1.1 }; char *file = "student.dat"; std::fstream fin; int place = (sizeof st2); fin.open(file,std::ios_base::out|std::ios_base::in|std::ios_base::app|std::ios_base::binary); fin.write((char *)&st2, sizeof st2); fin.seekg(-place,std::ios_base::end); //访问的位置是最后一个结构体的位置 while (fin.read((char*)&st2,sizeof st1)) { std::cout<< st2.num << st2.name << st2.score << std::endl; } fin.close(); }第十一章 输入输出和文件