类型名 & 引用名 = 某变量名
int n = 4;
int & r = n;//r引用了n,r的类型是int&
r = 4;
cout<
引用是从一而终
//在C中交换函数
void swap(int*a,int*b)
{
int tmp;
tmp=*a;*a=*b;*b=tmp;
}
int n1,n2;
swap(&n1,&n2);
//在C++中交换
void swap(int &a,int &b)
{//构建两个引用参数
int tmp;
tmp=a;a=b;b=tmp;
}
int n1,n2;
swap(n1,n2);
int n = 4;
int & SetValue()
{
return n;
}
int main()
{
SetValue()=40;
cout<
int n;
const int &r = n;//r的类型是const int &
不能通过常引用去修改其引用的内容
int n = 100;
const int &r = n;
r = 300;//出错
const int MAX_VAL = 23;
const double Pi = 3.14;
const char * SCHOOL_NAME = "BIT";
不可通过常量指针修改其指向的内容
int n,m;
const int *p = &n;
*p = 5;//非法
n = 4;
p = &m;//常量指针的指向可以变化
不能把常量指针赋值给非常量指针,反过来可以
const int *p1;
int *p2;
p1 = p2;//ok
p2 = p1;//非法,因为常量内容不可修改,所以不能把地址告诉非常量指针从而使得它来修改常量
p2 = (int*)p1;//强制类型转化
函数参数为常量指针时,可避免函数内部不小心改变参数指针所指地方的内容
void MyPrintf(const char*p)
{
strcpy(p,"this");//报错
printf("%s",p);
}
分配一个变量:
P = new T;
T是任意类型名,P是类型名为T*
的指针
动态分配出一片大小为sizeof(T)
字节的内存空间,并且将该内存空间的起始地址赋值给P
int *pn;
pn = new int;
*pn = 5;
分配一个数组:
P = new T[N];
T:任意类型名
P:类型为T*
的指针
N:要分配的数组元素的个数,可以是类型表达式
动态分配出一片大小为N*sizeof(T)
字节的内存空间,并将该内存空间的起始地址赋值给P
int *pn;
int i = 5;
pn = new int[i * 20];
pn[0] = 20;
delete 指针;//该指针必须指向new出来的空间
int *p = new int;
*p = 5;
delete p;
delete p;//只能释放一次
delete [ ]指针;
int *p = new int[20];
p[0] = 1;
delete [] p;
函数调用是有时间开销的,如果函数本身只有几条语句,执行非常快,而且函数被反复执行很多次,相比之下调用函数所产生的这个开销就会显得比较大,不用参数入栈
为了减少函数调用的开销,引入了内敛函数机制
编译器处理对内联函数的调用语句时,是将整个函数的代码插入到调用语句处,而不会产生调用函数的语句
inline int Max(int a,int b)
{
if(a > b)
{
return a;
}
return b;
}
一个或者多个函数,名字相同,然而参数个数或参数类型不相同
编译器根据调用语句的中的实参的个数和类型判断应该调用哪个函数
int Max(double f1,double f2){}
int Max(int n1,int n2){}
int Max(int n1,int n2,int n3){}
Max(3.4,2.5;//1
Max(2,4);//2
Max(1,2,3);//3
Max(3,2.4);//报错
定义函数的时候可以让最右边的连续若干个参数有缺省值
void func(int x1,int x2 = 2,int x3 = 3){}
func(10);//func(10,2,3)
func(10,8);//func(10,8,3)
func(10,,8);//非法,只能最右边的连续若干个参数缺省
输入矩形的长和宽,输出面积和周长
长宽变量和得到长宽数据,求面积,求体积三个函数封装到矩形类
长宽变量称为该矩形类的成员变量,三个函数称为该类的成员函数
成员变量和成员函数统称为类的成员
实际上,“类"看上去就像"带函数的结构”
class CRectangle
{//进行一波封装
public:
int w,h;
int Area()
{
return w*h;
}
int Perimeter()
{
return 2*(w+h);
}
void Init(int w_,int h_)
{
w = w_;
h = h_;
}
};
int main()
{
int w,h;
CRectangle r;//r是一个对象
cin>>w>>h;
r.Init(w,h);
cout<
对象名.成员名
CRectangle r1,r2;
r1.w = 5;
r2.Init(5,4);
指针->成员名
CRectangle r1,r2;
CRectangle *p1 = & r1;
CRectangle *p2 = & r2;
p1->w =5;
p2->Init(5,4);
引用名.成员名
CRectangle r2;
CRectangle &rr = r2;
rr.w = 5;
rr.Init(5,4);//rr值改变,则r2值也改变
class CRectangle
{//进行一波封装
public:
int w,h;
int Area();
int Perimeter();
void Init(int w_,int h_);
};
int CRectangle::Area()
{
return w*h;
}
int CRectangle::erimeter()
{
return 2*(w+h);
}
void CRectangle::Init(int w_,int h_)
{
w = w_;
h = h_;
}
class CEmployee
{
private:
char szName[30];
public:
int salary;
void setName(char* name);
void getName(char* name);
void averageSalary(CEmployee e1, CEmployee e2);
};
void CEmployee::setName(char* name)
{
strcpy(szName, name);//ok
}
void CEmployee::getName(char* name)
{
strcpy(name, szName);//ok
}
void CEmployee::averageSalary(CEmployee e1, CEmployee e2)
{
cout << e1.szName;//ok,访问同类其它对象私有成员
salary = (e1.salary + e2.salary) / 2;
}
int main()
{
CEmployee e;
strcmp(e.szName, "Tom");//no,不能访问私有成员
e.setName("Tom");
e.salary = 5000;
return 0;
}
设置私有成员的机制,叫"隐藏"
隐藏的目的是强制对成员变量的访问一定要通过成员函数进行,那么以后成员变量的类型等属性修改后,只需要更改成员函数即可.否则所有直接访问成员变量的语句都需要修改
class Complex
{
private:
double real, imag;
public:
void Set(double r, double i);
};//编译器会自动生成默认构造函数
Complex c1;//默认构造函数被调用,无参数
Complex* pc = new Complex;//默认构造函数被调用,无参数
class Complex
{
private:
double real, imag;
public:
Complex(double r, double i=0);
};
Complex::Complex(double r, double i)
{
real = r;
imag = i;
}
Complex c1;//报错,缺少构造函数的参数
Complex* pc = new Complex;//报错,没有参数
Complex c1(2);//ok
Complex c1(2,4);//ok
Complex* pc = new Complex(3,4);//ok
class Complex
{
private:
double real, imag;
public:
void Set(double r, double i);
Complex(double r);
Complex(double r, double i=0);
Complex(Complex c1, Complex c2);
};
Complex::Complex(double r, double i)
{
real = r;
imag = i;
}
Complex::Complex(double r)
{
real = r;
imag = 0;
}
Complex::Complex(Complex c1, Complex c2)
{
real = c1.real + c2.real;
imag = c1.imag + c2.imag;
}
Complex c1(3);//{3,0}
Complex c2(1, 2);//{1,2}
Complex c3(c1, c2);//{4,2}
class CSample
{
int x;
public:
CSample()
{
cout << "Constructor 1 Called" << endl;
}
CSample(int n)
{
x = n;
cout << "Constructor 2 Called" << endl;
}
};
int main()
{
CSample array1[2];//1 1
CSample array2[2] = { 4,5 };//2 2
CSample array3[2] = { 3 };//2 1
CSample* array4 = new CSample[2];//1 1
delete[]array4;
return 0;
}
class Test
{
public:
Test(int n) {} //(1)
Test(int n, int m) {}//(2)
Test() {} //(3)
};
Test array1[3] = { 1,Test(1,2) };//1 2 3
Test array2[3] = { Test(3,2),Test(1,2),1 };//2 2 1
Test* pArray[3] = { new Test(4),new Test(1,2) };//1 2
//上面这个语句只会生成两个对象
//因为这是指针创建的,如果为指定含义则指针为空而不创建
只有一个参数,即对同类对象的引用
形如X::X(X&)
或X::X(const X&)
,二者选一
后者能以常量对象作为参数,使用更多
class Complex
{
private:
double real, imag;
};
Complex c1;
//调用缺省无参构造函数
Complex c2(c1);
//调用缺省的无复制构造函数,将c2初始化成和c1一样
如果没有定义复制构造函数,那么编译器生成默认复制构造函数.默认的复制构造函数完成复制功能
class Complex
{
public:
double real, imag;
Complex() {}
Complex(const Complex& c)
{
real = c.real;
imag = c.imag;
cout << "Copy来的";
}
};
Complex c1;
Complex c2(c1);
用一个对象去初始化同类的另一个对象时
某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用
如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数将被调用
class A
{
public:
int v;
A(int n)
{
v = n;
};
A(const A &a)
{
v = a.v;
cout << "OK";
}
};
A Func()
{
A b(4);
return b;
}
int main()
{
cout << Func().v << endl;//ok4
return 0;
}
注意:对象间赋值并不导致复制构造函数被调用
class CMyclass
{
public:
int n;
CMyclass()
{};
CMyclass(CMyclass &c)
{
n = 2 * c.n;
}
};
int main()
{
CMyclass c1, c2;
c1.n = 5;
c2 = c1;
CMyclass c3(c1);
cout << c2.n;//5
cout << c3.n;//10
}
void fun(CMyclass obj_)
{
cout << "ok" << endl;
}
void fun(const CMyclass &obj)
这样的函数在调用的时候生成形参会引发复制构造函数调用,开销比较大
可以考虑使用CMyclass&引用类型作为参数
希望确保实参的值在函数中不应被改变,那么可以加上const
class Complex
{
public:
double real, imag;
Complex(int i)
{//类型转换构造函数
cout << "转换" << endl;
real = i;
imag = 0;
}
Complex(double r, double i)
{
real = r;
imag = i;
}
};
int main()
{
Complex c1(7, 8);
Complex c2 = 12;
c1 = 9;
//本身是类型不匹配,但是因为有了类型转化函数后就被转换成一个临时的Complex对象
cout << c1.real << c1.imag << endl;
}//转换9 0
class String
{
private:
char *p;
public:
String()
{
p = new char[10];
}
~String();
};
String::~String()
{
delete[]p;
}
对象数组生命周期结束时,对象数组的每个元素的析构函数都会被调用
class Ctest
{
public:
~Ctest()
{
cout << "释放" << endl;
}
};
int main()
{
Ctest array[2];
cout << "End" << endl;
return 0;
}//释放释放
delete 运算导致析构函数调用
若new一个对象数组,那么用delete释放时应该写[ ].否则只delete一个对象
Ctest * pTest;
pTest = new Ctest;//构造
delete pTest;//析构
pTest = new Ctest[3];//构造三次
delete [] pTest;//析构三次
析构函数在对象作为函数返回值返回后被调用
class CMyclass
{
public:
~CMyclass()
{
cout << "哦" << endl;
}
};
CMyclass obj;
CMyclass fun(CMyclass sobj)
{//sobj这个形参在使用完后会被释放产生一个哦
return sobj;
}
int main()
{
obj = fun(obj);
//fun(obj)是一个临时对象,在使用完后也会消亡产生哦
return 0;
//最终程序结束,obj释放产生一个哦
}//哦哦哦
class Demo
{
int id;
public:
Demo(int i)
{
id = i;
cout << "生" << id << endl;
}
~Demo()
{
cout << "亡" << id << endl;
}
};
Demo d1(1);//此句最先执行,于是引发构造函数
void Func()
{
static Demo d2(2);//静态局部变量不会消亡,仍然会保存其值
Demo d3(3);
cout << "func" << endl;
}
int main()
{
Demo d4(4);
d4=6;
cout<<"main"<
c++到c的翻译
//C++
class CCar
{
public:
int price;
void SetPrice(int p);
};
void CCar::SetPrice(int p)
{
price = p;
}
int main()
{
CCar car;
car.SetPrice(2000);
return 0;
}
//翻译成C
struct CCar
{
int price;
};
void SetPrice(struct CCar * this, int p)
{
this->price = p;
}
int main()
{
struct CCar car;
SetPrice( &car, 2000);
return 0;
}
非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针
静态成员函数不能使用
因为静态成员函数并不具体作用于某个对象
因此静态成员函数的真是参数的个数,就是程序中写出的参数个数
class Complex
{
public:
double real, imag;
void Print()
{
cout << real << "," << imag;
}
Complex(double r, double i) : real(r), imag(i)
{}
Complex AddOne()
{
this->real++;//等价于real++
this->Print();//等价于Pringt
return *this;
}
};
int main()
{
Complex c1(1, 1), c2(0, 0);
c2 = c1.AddOne();
return 0;
}//2,1
this的意义
class A
{
int i;
public:
void Hello()
{
cout << "hello" << endl;
}
};//void Hello(A*this){cout << "hello" << endl;}
int main()
{
A *p=NULL;
p->Hello();//Hello(p);
}//输出:hello,不报错
class A
{
int i;
public:
void Hello()
{
cout << i << "hello" << endl;
}
};//void Hello(A*this){cout << this->i << "hello" << endl;} 此时出现this,而原指针NULL则会报错
int main()
{
A *p=NULL;
p->Hello();//Hello(p);
}//报错
加static关键字
普通成员变量每个对象有各自的一份
静态成员变量一共就一份,为所有对象共享
sizeof运算符不计算静态成员变量
普通成员函数必须作用于某个对象
静态成员函数并不具体作用于某个对象
静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在
静态成员函数本质上是全局函数
设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去像是一个整体
比如考虑一个随时需要知道矩形面积和综述的图形处理程序
class CRectangle
{
private:
int w, h;
static int nTotalArea;
static int nTotalNumber;
public:
CRectangle(int w_, int h_);
~CRectangle();
static void PrintTotal();
};
CRectangle::CRectangle(int w_, int h_)
{
w = w_;
h = h_;
nTotalNumber++;
nTotalArea += w * h;
}
CRectangle::~CRectangle()
{
nTotalNumber--;
nTotalArea -= w * h;
}
void CRectangle::PrintTotal()
{
cout << nTotalNumber << "," << nTotalArea << endl;
}
int CRectangle::nTotalArea = 0;
int CRectangle::nTotalNumber = 0;
/*必须在定义类的文件中对静态成员变量进行一次说明
或初始化。否则编译能通过,链接不能通过*/
int main()
{
CRectangle r1(3,3),r2(2,2);
//cout<
静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数
void CRectangle::PrintTotal()
{
cout<
在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象
这些临时对象在消亡时会调用析构函数,减少nTotalNumber和nTotalArea的值,但这些临时对象在生成时却又没有增加这些值
解决办法:自己写复制构造函数
CRectangle::CRectangle(CRectangle &r)
{
w = r.w; h = r.h;
nTotalNumber++;
nTotalArea += w*h;
}
有成员对象的类叫封闭类
class CTyre
{//轮胎类
private:
int radius;
int width;
public:
CTyre(int r, int w) : radius(r), width(w)
{}
};
class CEngine
{//引擎类
};
class CCar
{//汽车类就是一个封闭类
private:
int price;
CTyre tyre;
CEngine engine;
public:
CCar(int p,int tr,int w);
};
CCar::CCar(int p, int tr, int w) :price(p),tyre(tr,w)
{
};
int main()
{
CCar car(2000,17,225);
return 0;
}
上例中如果CCar类不定义构造函数,则此语句会编译出错:CCar car;
因为编译器不明白car.type该如何初始化,car.type定义了有参构造函数,而没有无参构造函数
所以任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象,是如何初始化的
具体的做法就是:通过封闭类的构造函数的初始化列表
成员对象初始化列表中的参数可以是任意复杂的表达式,可以包括函数,变量只要表达式中的函数或变量有定义就行
封闭类对象生成时,先执行所有对象成员的构造函数,然后才执行封闭类的构造函数
对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关
当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数.次序和构造函数的调用次序相反
class CTyre
{
public:
CTyre()
{
cout << "CTyre 创建" << endl;
}
~CTyre()
{
cout << "Ctyre 消亡" << endl;
}
};
class CEngine
{
public:
CEngine()
{
cout << "CEngine 创建" << endl;
}
~CEngine()
{
cout << "CEngine 消亡" << endl;
}
};
class CCar
{
private:
CEngine engine;
CTyre tyre;
public:
CCar()
{
cout << "CCar 创建" << endl;
}
~CCar()
{
cout << "CCar 消亡" << endl;
}
};
int main()
{
CCar car;
return 0;
}
/*CEngine 创建
CTyre 创建
CCar 创建
CCar 消亡
Ctyre 消亡
CEngine 消亡*/
说明b2.a是用类A的复制构造函数初始化的.而且调用复制构造函数时的实参就是b1.a
class A
{
public:
A()
{
cout << "default" << endl;
}
A(A &a)
{
cout << "copy" << endl;
}
};
class B
{
A a;
};
int main()
{
B b1, b2(b1);
return 0;
}//default copy
如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字
const Complxe c1;
void Complex() const;
两个成员函数,名字和参数表都一样,但是一个是const,一个不是,算重载
对象作为函数参数时,生成该参数需要调用复制构造函数,效率低.指针作参数,代码不好看 const Complex & C1
一个类的友元函数可以访问该类的私有成员
class CCar;//提前声明CCar类,以便后面的CDrive类使用
class CDriver
{
public:
void ModifyCar(CCar *pCar);//改装汽车
};
class CCar
{
private:
int price;
friend int MostExpensiveCar(CCar cars[], int total);//声明友元
friend int CDriver::ModifyCar(CCar *pCar);//声明友元
};
void CDriver::ModifyCar(CCar *pCar)
{
pCar->price += 1000;
}
int MostExpensiveCar(CCar cars[], int total)
{//求最贵汽车的价格
int tmpMax = -1;
for (int i = 0; i < total; ++i)
{
if (cars[i].price > tmpMax)
{
tmpMax = cars[i].price;
}
}
return tmpMax;
}
int main()
{
return 0;
}
如果A是B的友元类,那么A的成员函数可以访问B的私有成员
class CCar
{
private:
int price;
friend class CDriver;
};
class CDriver
{
public:
CCar myCar;
void ModifyCar()
{//因CDriver是CCar的友元类,故此处可以访问其私有成员
myCar.price+=1000;
}
};
int main()
{
return 0;
}
友元类之间的关系不能传递,不能继承
例如可以实现对象与对象之间的加减
返回值类型 operator 运算符(形参表)
{
...
}
class Complex
{
public:
double real, imag;
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i){}
Complex operator-(const Complex &c);
};
Complex operator+(const Complex &a,const Complex &b)
{
return Complex(a.real+b.real,a.imag+b.imag);
}//返回一个临时对象
Complex Complex::operator-(const Complex &c)
{
return Complex(real -c.real,imag-c.imag);
}//返回一个临时对象
int main()
{
Complex a(4, 4), b(1, 1), c;
c = a + b;//等价于c=operator+(a,b)
cout << c.real << "," << c.imag << endl;
cout << (a - b).real << "," << (a - b).imag << endl;
//a - b等价于a.operator-(b)
return 0;
}//5,5 3,3
有时希望赋值运算符两边的类型可以不匹配,比如,把int类型赋值给一个Complex对象,或把一个char *类型的字符串赋值给一个字符串对象,此时需要重载赋值运算符 =
赋值运算符 = 只能重载为成员函数
class String
{
private:
char *str;
public:
String() : str(new char[1])
{
str[0] = 0;
}
const char *c_str()
{
return str;
}
String &operator=(const char *s);
String::~String()
{
delete[] str;
}
};
String &String::operator=(const char *s)
{//重载 = 以使得 obj = Hello 能够成立
delete[] str;
str = new char[strlen(s) + 1];
strcpy(str, s);
return *this;
}
int main()
{
String s;
s = "GoodLuck";//等价于s.operator=("GoodLuck");
cout << s.c_str() << endl;
String s2 = "hello";//这条语句是初始化语句不是赋值语句,会出错
return 0;
}
如不定义自己的赋值运算符,那么s1=s2实际上导致s1.str和s2.str指向同一个地方
String s1,s2;
s1 = "this";
s2 = "that";
s1 = s2;//导致s1的指针指向了s2,s1此时为内存垃圾
如果s1对象消亡,析构函数将释放s1.str指向的空间,则s2消亡时还要释放一次,不妥
另外,如果执行s1 = “other”,会导致s2.str指向的地方被delete
因此要在class String中添加成员函数
String & operator = (const String & s)
{
delete [] str;
str = new char[strlen(s.str) + 1];
strcpy( str, s.str);
return * this;
}
但是如果运行一下代码还是会出错
MyString s;
s = "Hello";
s = s;
应修改为
String & operator = (const String & s)
{
if( this == & s)
{//防止左右两边一样
return * this;
}
delete [] str;
str = new char[strlen(s.str) + 1];
strcpy( str, s.str);
return * this;
}
class Complex
{
double real, imag;
public:
Complex(double r, double i) : real(r), imag(i){};
Complex operator+(double r);
};
Complex Complex::operator+( double r)
{//可以解释c+5,但是不能解释5+c
return Complex(real + r,imag);
}
一般来说重载为成员函数不能满足使用要求,重载为普通函数又不能访问类的私有成员,所以需要将运算符重载为友元
//想要解释5+c,需将+重载为普通函数
Complex operator + (double r,const Complex & c)
{
return Complex( c.real + r, c.imag);
}
//在Complex类里需要如下定义,来实现访问
friend Complex operator + (double r,const Complex & c);
编写一个类,能如下使用
int main()
{
CArray a;//开始数组是空的
for (int i = 0; i < 5; ++i)
{
a.push_back(i);
//要用动态分配的内存来存放数组元素,需要一个指针成员变量
}
CArray a2, a3;
a2 = a;//要重载"="
for (int i = 0; i < a.length(); ++i)
{
cout << a2[i] << " ";
//要重载"[]"
}
cout << endl;
a2 = a3;//a2是空的
for (int i = 0; i < a2.length(); ++i)
{//a2.length()返回0
cout << a2[i] << " ";
}
cout << endl;
a[3] = 100;
CArray a4(a);
for (int i = 0; i < a4.length(); ++i)
{
cout << a4[i] << " ";
}
return 0;
}
//0 1 2 3 4
//0 1 2 100 4
class CArray
{
int size;//数组个数
int *ptr;//指向动态分配的数组
public:
CArray(int s = 0);//s代表数组元素个数
CArray(CArray &a);
~CArray();
void push_back(int v);//用于在数组位补添加一个元素v
CArray &operator=(const CArray &a);//用于数组对象间的赋值
int length()
{//返回数组元素个数
return size;
}
int & CArray::operator[](int i)//返回值为int不行,不支持a[i]=4
//用以支持根据下标访问数组元素
//如n = a[i]和a[i] = 4;这样的语句
{
return ptr[i];
}
};
CArray::CArray(int s) : size(s)
{
if (s == 0)
{
ptr = NUll;
}
else
{
ptr = new int[s];
}
}
CArray::CArray(CArray &a)
{
if (!a.ptr)
{
ptr = NULL;
size = 0;
return;
}
ptr = new int[a.size];
memcpy(ptr, a.ptr, sizeof(int) * a.size);
size = a.size;
}
CArray::~CArray()
{
if (ptr)
{
delete[] ptr;
}
}
void CArray::push_back(int v)
{//在数组尾部添加一个元素
if(ptr)
{
int *tmpPtr=new int [size+1];//重新分配空间
memcpy(tmpPtr,ptr,sizeof(int)*size);//拷贝原数组内容
delete [] ptr;
ptr=tmpPtr;
}
else
{//数组原本是空的
ptr=new int[1];
}
ptr[size++]=v;//加入新的数组元素
}
CArray & CArray::operator=(const CArray &a)
{//重载赋值号的作用是使“=”左边对象里存放的数组,大小和内容都和右边的对象一样
if (ptr == a.ptr)
{//防止a=a 这样的赋值导致出错
return *this;
}
if (a.ptr == NULL)
{//如果a里面数组是空的
if (ptr)
{
delete[]ptr;
}
ptr = NULL;
size = 0;
return *this;
}
if (size < a.size)
{
if (ptr)
{
delete[] ptr;
}
ptr = new int[a.size];
}
memcpy(ptr, a.ptr, sizeof(int) * a.size);
size = a.size;
return *this;
}
cout<<5<<“this”;
cout.operator<<(5).operator<<(“this”);
假定下面程序输出为5hello,该补写什么
class CStudent
{
public:
int nAge;
};
int main()
{
CStudent s;
s.nAge = 5;
cout << s << "hello"<
假定c是Complex复数类对象,现在希望写"cout<
int main()
{
Complex c;
int n;
cin >> c >> n;
cout << c << "," << n;
return 0;
}
//13.2+133i 87
//13.2+133i,87
class Complex
{
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i)
{};
friend ostream &operator<<(ostream &os, const Complex &c);
friend istream &operator>>(istream &is, Complex &c);
};
ostream &operator<<(ostream &os, const Complex &c)
{
os << c.real << "+" << c.imag << "i";//a+bi
return os;
}
istream &operator>>(istream &is, Complex &c)
{
string s;
is >> s;
//将a+bi作为字符串读入,a+bi中间不能有空格
int pos = s.find("+", 0);
string sTmp = s.substr(0, pos);
//分离出代表实部的字符串
c.real = atof(sTmp.c_str());
//atof库函数能够将const char*指针指向的内容转换成float
sTmp = s.substr(pos + 1, s.length() - pos - 2);
//分离出代表虚部的字符串
c.imag = atof(sTmp.c_str());
return is;
}
class Complex
{
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(r)
{}
operator double()
{//重载强制类型转换运算符double
return real;
}
};
int main()
{
Complex c(1.2, 3.4);
cout << (double) c << endl;//输出1.2
double n = 2 + c;//等价于double n=2+c.operator double()
cout << n;//输出3.2
}
自增运算符++,自减运算符-- 有前置后置之分。为了区分所重载的是前置运算符还是后置运算符,c++规定:
int main()
{
CDemo d(5);
cout << (d++) << ",";//等价于 d.operator++(0)
cout << d << ",";
cout << (++d) << ",";//等价于 d.operator++()
cout << d << endl;
cout << (d--) << ",";//等价于 operator-(d,0)
cout << d << ",";
cout << (--d) << ",";//等价于 operator-(d)
cout << d << endl;
return 0;
}
//要求输出
//5 6 7 7
//7 6 5 5
class CDemo
{
private:
int n;
public:
CDemo(int i = 0) : n(i)
{}
CDemo &operator++();//前置
CDemo operator++(int);//后置
operator int()
{
return n;
}
friend CDemo &operator--(CDemo &);//前置
friend CDemo operator--(CDemo &, int);//后置
};
CDemo &CDemo::operator++()
{//前置++
++n;
return *this;
}//++s即为:s.operator++();
CDemo CDemo::operator++(int k)
{//后置++
CDemo tmp(*this);//记录修改前的对象
n++;
return tmp;//返回修改前的对象
}//s++即为:s.operator++(0);
CDemo & operator--(CDemo &d)
{//前置--
d.n--;
return d;
}//--s 即为:operator--(s);
CDemo operator--(CDemo &d,int)
{//后置--
CDemo tmp(d);
d.n--;
return tmp;
}//s--即为:operaor--(s,0);
class CStudent
{
private:
string sName;
int nAge;
public:
bool IsThreeGood()
{};
void SetName(const string &name)
{
sName = name;
}
}
class CUndergraduateStudent : public CStudent
{
private:
int nDepartment;
public:
bool IsThreeGood()
{};//覆盖
bool CanBaoYan()
{};
};//派生类的写法是: 类名:public 基类名
class CGraduatedStudent: public CStudent
{
private:
int nDepartment;
char szMentorName[20];
public:
int CountSalary(){};
};
继承实例程序:学籍管理
class CStudent
{
private:
string name;
string id;
char gender;//'F'女,'M'男
int age;
public:
void PrintInfo();
void SetInfo(const string &name_, const string &id_, int age_, char gender_);
string GetName()
{
return name;
}
};
class CUndergraduateStudent : public CStudent
{//本科生类,继承了CStudent类
private:
string department;
public:
void QualifieldForBaoyan()
{//给予保研资格
cout << "qualified for baoyan" << endl;
}
void PrintInfo()
{//覆盖
CStudent::PrintInfo();//调用基类的PrintInfo
cout << "Department:" << department << endl;
}
void SetInfo(const string &name_, const string &id_, int age_, char gender_, const string &department_)
{
CStudent::SetInfo(name_, id_, age_, gender_);//调用基类的SetInfo
department = department_;
}
};
int main()
{
CUndergraduateStudent s2;
s2.SetInfo("Harry","11889922",19,'M',"Computer");
cout<
class CMaster;
class CDog
{
CMaster * pm;
};
class CMaster
{
CDog * dogs[10];
};
class base
{
int j;
public:
int i;
void func();
};
class derived : public base
{
public:
int i;
void access();
void func();
};
void derived::access()
{
j=5;//error
i=5;//引用派生类的i
base::i=5;//引用基类的i
func();//派生类的
base::func();//基类的
}
class Father
{
private:
int nPrivete;
public:
int nPublic;
protected:
int nProtected;
};
class Son:public Father
{
void AccessFather()
{
nPublic=1;
nPrivate=1;//wrong
nProtected=1;
Son f;
f.nProtected=1;//wrong
}
};
class Bug
{
private:
int nLegs;
int nColor;
public:
int nType;
Bug(int legs, int color);
void PrintBug()
{};
};
class FlyBug : public Bug
{
int nWaings;
public:
FlyBug(int legs, int color, int wings);
};
Bug::Bug(int legs, int color)
{
nLegs = legs;
nColor = color;
}
//错误写法
FlyBug::FlyBug(int legs, int color, int wings)
{
nLegs=legs;//不能访问
nColor=color;//不能访问
}
//正确写法
FlyBug::FlyBug(int legs, int color, int wings) : Bug(legs, color)
{
nWaings = wings;
}
class base { };
class derived : public base { };
base b;
derived d;
class CBase
{
public:
virtual void SomeVirtualFunction(){}
};
class CDerived:public CBase
{
public:
virtual void SomeVirtualFunction(){}
};
int main()
{
CDerived ODerived;
CBase * p=&ODerived;
p->SomeVirtualFunction();//调用哪个虚函数取决于p指向哪种类型的对象
return 0;
}
class CBase
{
public:
virtual void SomeVirtualFunction()
{}
};
class CDerived : public CBase
{
public:
virtual void SomeVirtualFunction()
{}
};
int main()
{
CDerived ODerived;
CBase &r = &ODerived;
r.SomeVirtualFunction();//调用哪个虚函数取决于r引用哪种类型的对象
return 0;
}
class base
{
virtual int get();
}
int base::get(){}
virtual关键字只用在类定义里的函数声明中,写函数体时不用
构造函数和静态成员函数不能是虚函数
class CBase
{
public:
virtual void SomeVirtualF();
};
class CDerived:public Cbase
{
public:
virtual void SomeVirtualF();
};
int main()
{
Cderived ODerived;
CBase *p=&ODerived;
p->SomeVirtualF();
//调用哪个虚函数取决于p指向哪种类型的对象
return 0;
}
例,输入
R 3 5
C 9
T 3 4 5
#include
#include
#include
using namespace std;
class CShape
{
public:
virtual double Area() = 0;//纯虚函数
virtual void PrintInfo() = 0;
};
class CRectangle : public CShape
{
public:
int w, h;
virtual double Area()
{
return w * h;
}
virtual void PrintInfo();
{
cout << "Rectangle:" << Area() << endl;
}
};
class CCircle : public CShape
{
public:
int r;
virtual double Area();
{
return 3.14 * r * r;
}
virtual void PrintInfo();
{
cout << "Circle:" << Area() << endl;
}
};
class CTriangle : public CShape
{
public:
int a, b, c;
virtual double Area();
{
double p = (a + b + c) / 2.0;
return sqrt(p * (p - a) * (p - b) * (p - c));
}
virtual void PrintInfo();
{
cout << "Triangle:" << Area() << endl;
}
};
CShape *pShapes[100];
int MyCompare(const void *s1, const void *s2);
int main()
{
int i;
int n;
CRectangle *pr;
CCircle *pc;
CTriangle *pt;
cin >> n;
for (i = 0; i < n; i++)
{
char c;
cin >> c;
switch (c)
{
case 'R':
pr = new CRectangle();
cin >> pr->w >> pr->h;
pShapes[i] = pr;
break;
case 'C':
pc = new CCircle();
cin >> pc->r;
pShapes[i] = pc;
break;
case 'T':
pt = new CTriangle();
cin >> pt->a >> pt->b >> pt->c >> c;
pShapes[i] = pt;
break;
}
}
qsort(pShapes, n, sizeof(CShape *), MyCompare);
for (i = 0; i < n; i++)
{
pShapes[i]->PrintInfo();
}
return 0;
}
int MyCompare(const void *s1, const void *s2)
{
double a1, a2;
CShape **p1;
//s1,s2是void*,不可写*s1来取得s1指向的内容
CShape **p2;
p1 = (CShape **) s1;
//s1,s2指向pShapes数组中的元素,数组元素的类型是CShape*
p2 = (CShape **) s2;
//p1,p2都是指向指针的指针,类型为CShape**
a1 = (*p1)->Area();
//*p1的类型是CShape*,是基类指针,故此句为多态
a2 = (*p2)->Area();
if (a1 < a2)
{
return -1;
}
else if (a2 < a1)
{
return 1;
}
else
{
return 0;
}
}
如果添加新的几何形体,比如五边形,则只需要从CShape派生出CPentagon,以及在main中的switch语句中增加一个Case,其余部分不变
class Base
{
public:
void fun1()//this是基类指针,fun2()是虚函数,所以是多态
{ fun2(); }
virtual void fun2()
{ cout << "base fun2()" << endl; }
};
class Derived : public Base
{
public:
virtual void fun2()
{ cout << "Derived:fun2()" << endl; }
};
int main()
{
Derived d;
Base *pBase = &d;
pBase->fun1();
return 0;
}
//输出Derived:fun2()
在非构造函数,非析构函数的成员函数中调用虚函数,是多态
在构造函数和析构函数中调用虚函数,不是多态
编译时即可确定,调用的函数时自己的类货基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数
派生类中和基类中虚函数同名同参数表的函数,不加virtual也自动成为虚函数
class myclass
{
public:
virtual void hello()
{
cout << "hello from myclass" << endl;
}
virtual void bye()
{
cout << "bye from myclass" << endl;
}
};
class son : public myclass
{
public:
void hello()
{
cout << "hello from son" << endl;
}
son()
{
hello();
}
~son()
{
bye();
}
};
class grandson : public son
{
public:
void hello()
{
cout << "hello from grandson" << endl;
}
void bye()
{
cout << "bye from grandon" << endl;
}
grandson()
{
cout << "constructing grandson" << endl;
}
~grandson()
{
cout << "destructing grandson" << endl;
}
};
int main()
{
grandson gson;
son *pson;
pson = &gson;
pson->hello();
return 0;
}
多态实现的关键
每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中放着虚函数表的指针.虚函数表中列出了该类的虚函数地址.多出来的4个字节就是用来放虚函数表的地址的
通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数
但是删除一个派生类的对象时,应该先调用派生类的析构函数,然后调用基类的析构函数
解决办法:把基类的析构函数声明为virtual
派生类的析构函数可以virtual不进行声明
通过基类的指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数
一个类如果定义了虚函数,则应该将析构函数也定义成虚函数
class son
{
public:
~son()
{
cout << "bye from son" << endl;
}
};
class grandson : public son
{
public:
~grandson()
{
cout << "bye from grandson" << endl;
}
};
int main()
{
son *pson;
pson = new grandson();
delete pson;
return 0;
}//并没有执行~son()
class son
{
public:
virtual ~son()
{
cout << "bye from son" << endl;
}
};
class grandson : public son
{
public:
~grandson()
{
cout << "bye from grandson" << endl;
}
};
int main()
{
son *pson;
pson = new grandson();
delete pson;
return 0;
}//引起执行~son()
没有函数体的虚函数
class A
{
private:
int s;
public:
virtual void Print() = 0;//纯虚函数
void fun()
{
cout << "fun";
}
};
包含纯虚函数的类叫抽象类
抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
抽象类的指针和引用可以指向由抽象类派生出来的类的对象
A a;//错,A是抽象类,不能创建对象
A* pa;//ok,可以定义抽象类的指针和引用
pa = new A;//错误,A是抽象类,不能创建对象
在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部不能调用纯虚函数
如果一个类从抽象类派生而来,那么当且仅当它实现了基类中的所有纯虚函数,他才能成为非抽象类
#include
using namespace std;
int main()
{
int x, y;
cin >> x >> y;
freopen("test.txt", "w", stdout);
if (y == 0)
{
cerr << "error." << endl;
}
else
{
cout << x / y;
}
return 0;
}
istream & getline(char * buf,int bufsize);
istream & getline(char * buf,int bufsize,char delim);
读入一行或先到bufsize,或读到delim为止,哪个先到算哪个
bool eof();
判断输入流是否结束
int peek();
返回下一个字符,但不从流中去掉
需要#include
int n = 10;
cout << n << endl;
cout << hex << n << endl;
cout << dec << n <<endl;
cout << oct << n << endl;
成员函数cout.precision(5);
流操作算子cout<< setprecision(5);可以连续输出
指定输出浮点数的有效位数,非定点方式输出时
指定输出小数点后的有效位数,定点方式输出时
setiosflags(ios::fixed);以小数点位置固定的方式输出
resetiosflags(ios::flags);取消
int w = 4;
char string[10];
cin.width(5);
while (cin >> string)
{
cout.width(w++);
cout << string << endl;
cin.width(5);;
}
输入1234567890
输出
1234
5678
90
double x = 1234567.89;
double y = 12.34567;
cout << setprecision(5) << x << y << endl;
1.2346e+006 12.346//保留5位有效数字
cout << fixed <<setprecision(5) << x << << y << endl;
1234567.89000 12.34567//保留小数点后面5位
cout << scientific << setprecision(5) << x << y << endl;
1.23457e+006 1.23457e+001//科学计数法输出,且保留小数点后5位
cout << showpos << fixed << setw(12) << setfill('*') << 12.1 << endl;
***+12.10000//非负数要显示正好,输出宽度为12字符,宽度不足则用*替代
cout << noshowpos << setw(12) << left << 12.1 << endl;
12.10000****//非负数不显示正号,输出宽度为12字符,宽度不足则右边用填充字符填充
cout << setw(12) << right << 12.1 << endl;
****12.10000//输出宽度为12字符,宽度不足则左边用填充字符填充
cout << setw(12) << internal << -12.1 << endl;
-***12.10000//宽度不足时,负号和数值分列左右,中间用填充字符填充
ostream &tab (ostream &output)
{
return output << '\t';
}
cout << "a" << tab << 'b' << endl;
//a b
is 派生出 istream 和 ostream
istream 派生出 ifstream 和 iostream
ostream 派生出 iostream 和 ofstream
iostream派生出fstream
#include
ofstream outFile("clients.dat", ios::out|ios::binary);//创建文件
ios::out文件打开方式
ios::out 输出到文件,删除原有内容
ios::app 输出到文件,保留原有内容,总是在尾部添加
ios::binary 以二进制文件格式打开文件
ofstream fout;
fout.open("test.out", ios::out|ios::binary);
也可以先创建ofstream对象,再用open函数打开
if (!fout)
{
cout << "File open error!" << endl;
}判断是否打开成功
ofstream fout("a1.out", ios::app);//以添加方式打开
long location = fout.tellp();//取得写指针的位置
location = 10;
fout.seekp(location);//将写指针移动到第10个字节处
fout.seekp(location,ios::beg);//从头数location
fout.seekp(location,ios::cur);//从当前位置数location
fout.seekp(location,ios::end);//从尾部数location
location可以为负值
ifstream fin("a1.in", ios::ate);//打开文件,定位文件指针到文件尾
long location = fin.tellg();//取得读指针的位置
location = 10L;
fin.seekg(location);//将读指针移动到第10个字节处
fin.seekg(location,ios::beg);//从头数location
fin.seekg(location,ios::cur);//从当前位置数location
fin::seek(location,ios::end);//从尾部数location
#include
#include
#include
#include
using namespace std;
int main()
{
vector<int> v;
ifstream srcFile("in.txt", ios::in);
ofstream destFile("out.txt", ios::out);
int x;
while (srcFile >> x)
{
v.push_back(x);
}
sort(v.begin(), v.end());
for (int i = 0; i < v.size(); i++)
{
destFile << v[i] << " ";
}
destFile.close();
srcFile.close();
return 0;
}
ifstream 和 fstream 的成员函数
istream & read (char *s,long n);
ofstream 和 fstream的成员函数
istream & write (const char *s,long n);
#include
#include
using namespace std;
int main()
{
ofstream fout("some,dat", ios::out | ios::binary);
int x = 120;
fout.write((const char*)(&x), sizeof(int));
fout.close();
ifstream fin("some.dat", ios::in | ios::binary);
int y;
fin.read((char*)&y, sizeof(int));
fin.close();
cout << y << endl;
return 0;
}
#include
#include
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
ofstream OutFile("students.dat", ios::out | ios::binary);
while (cin >> s.name >> s.score)
{
OutFile.write((char *) &s, sizeof(s));
}
OutFile.close();
return 0;
}
#include
#include
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
ifstream inFile("students.dat", ios::in | ios::binary);
if (!inFile)
{
cout << "error" << endl;
return 0;
}
while (inFile.read((char *) &s, sizeof(s)))
{
int readedBytes = inFile.gcount();//看刚才读了多少字节
cout << s.name << " " << s.score << endl;
}
inFile.close();
return 0;
}
/*输入:
Tom 60
Jack 80
Jane 40*/
#include
#include
#include
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
fstream iofile("students.dat", ios::in | ios::out | ios::binary);
if (!iofile)
{
cout << "error!";
return 0;
}
iofile.seekp(2 * sizeof(s), ios::beg);//定位写指针到第三个记录
iofile.write("Mike", strlen("Mike") + 1);
iofile.seekg(0, ios::beg);//定位读指针到开头
while (iofile.read((char *) &s, sizeof(s)))
{
cout << s.name << " " << s.score << endl;
}
iofile.close();
return 0;
}
将src.dat 拷贝到 dest.dat
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 3)
{
cout << "File name missing!" << endl;
return 0;
}
ifstream inFile(argv[1], ios::binary | ios::in);//打开文件用于读
if (!inFile)
{
cout << "Source file open erroe." << endl;
return 0;
}
ofstream outFile(argv[2], ios::binary | ios::out);//打开文件用于写
if (!outFile)
{
cout << "New file open error." << endl;
inFile.close();//打开的文件一定要关闭
return 0;
}
char c;
while (inFile.get(c))
{
outFile.put(c);
}
outFile.close();
inFile.close();
return 0;
}
void swap(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}
void swap(double &x, double &y)
{
double temp = x;
x = y;
y = temp;
}
将此两个函数化为一类模版函数,用函数模版解决
template <class 类型参数1,class 类型参数2,...>
返回值类型 模版名(形参表)
{
函数体
};
template <class T>
void swap(T &x,T &y)
{
T temp = x;
x = y;
y = temp;
}
int main()
{
int n = 1,m = 2;
swap(n,m);//编译器自动生成void swap(int &,int &)函数
double f = 1.2,g = 2.3;
swap(f,g);//编译器自动生成void swap(double &,double &)函数
return 0;
}
template <class T1, class T2>
T2 print(T1 arg1,T2 arg2)
{
cout << arg1 << " " << arg2 << endl;
return arg2;
}
求数组最大元素的MaxElement函数模版
template<class T>
T MaxElement(T a[], int size)
{
T tmpMax = a[0];
for (int i = 1; i < size; i++)
{
if (tmpMax < a[i])
{
tmpMax = a[i];
}
}
return tmpMax;
}
template<class T>
T Inc(T n)
{
return 1 + n;
}
int main()
{
cout << Inc<double>(4) / 2;//输出2.5
return 0;
}
只要他们的形参表或类型参数表不用即可
template <class T1,class T2>
void print(T1 arg1, T2 arg2)
{
cout << arg1 << arg2 << endl;
}
template <class T>
void print(T arg1, T arg2)
{
cout << arg1 << arg2 << endl;
}
template <class T, class T2>
void print(T arg1, T arg2)
{
cout << arg1 << agr2 << endl;
}
匹配模版函数时,不进行类型自动转化
template <class T>
T my(T arg1, T arg2)
{
cout << arg1 << " " << arg2 << endl;
return arg1;
}
my(5,7);//int int
my(5.8,8.4);//double double
my(5,8.4);//报错
template <class 类型参数1, class 类型参数2, ...>
class 类模板名
{
成员函数和成员变量
};
template <typename 类型参数1, 类型参数2, ...>
class 类模板名
{
成员函数和成员变量
};
template<class T1, class T2>
class Pair
{
public:
T1 key;//关键字
T2 value;//值
Pair(T1 k, T2 v) : key(k), value(v)
{
};
bool operator<(const Pair<T1, T2> &p) const;
};
template<class T1, class T2>
bool Pair<T1, T2>::operator<(const Pair<T1, T2> &p) const
{
//Pair的成员函数operator <
return key < p.key;
}
int main()
{
Pair<string, int> student("Tom", 19);
//实例化出一个类Pair(string,int>
cout << student.key << " " << student.value;
return 0;
}
编译器由类模板生成类的过程叫类模板的实例化
template<class T>
class A
{
public:
template<class T2>
void Func(T2 t)
{
//成员函数模板
cout << t << endl;
}
};
int main()
{
A<int> a;
a.Func('K');//成员函数被实例化
a.Func("hello");//成员函数再次被实例化
return 0;
}
类模板的<类型参数表>中可以出现非类型参数
template<class T, int size>
class CArray
{
T array[size];
public:
void Print()
{
for (int i = 0; i < size; i++)
{
cout << array[i] << endl;
}
}
};
CArray<double, 40> a2;
CArray<int, 50> a3;//a2,a3属于不同的类
类模板从类模板派生
template<class T1, class T2>
class A
{
T1 v1;
T2 v2;
};
template<class T1, class T2>
class B : public A<T2, T1>
{
T1 v3;
T2 v4;
};
template<class T>
class C : public B<T, T>
{
T v5;
};
int main()
{
B<int, double> obj1;
C<int> obj2;
return 0;
}
//相当于
class B<int, double> : public A<double, int>
{
int v3;
double v4;
};
class A<double, int>
{
double v1;
int v2;
};
类模板从模板类派生
template<class T1, class T2>
class A
{
T1 v1;
T2 v2;
};
template<class T>
class B : public A<int, double>
{
T v;
};
int main()
{
B<char> obj1;//自动生成两个模板类A和B
return 0;
}
类模板从普通类派生
class A
{
int v1;
};
template <class T>
class B:public A
{
//所有从B实例化得到的类,都以A为基类
T v;
};
int main()
{
B<char> obj1;
return 0;
}
普通类从模板类派生
template <class T>
class A
{
T v1;
int n;
};
class B:public A<int>
{
double v;
};
int main()
{
B obj1;
return 0;
}
函数,类,类的成员函数作为类模板的友元
void Func1()
{
}
class A
{
};
class B
{
public:
void Func()
{
}
};
template<class T>
class Tmpl
{
friend void Func1();
friend class A;
friend void B::Func();
};//任何从Tmp1实例化来的类,都有以上三个友元
函数模板作为类模板的友元
template<class T1, class T2>
class Pair
{
private:
T1 key;
T2 value;
public:
Pair(T1 k, T2 v) : key(k), value(v)
{
};
bool operator<(const Pair<T1, T2> &p) const;
template<class T3, class T4>
friend ostream &operator<<(ostream &o, const Pair<T3, T4> &p);
};
template<class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2>&p)const
{
//小的意思就是关键字小
return key < p.key;
}
template <class T1,class T2>
ostream & operator << (ostream &o, const Pair<T1,T2> &p)
{
o << "(" << p.key << "," << p.value << ")";
return o;
}
int main()
{
Pair<string,int> student("Tom",29);
Pair<int,double>obj(12,3.14);
cout << student << " " << obj;
return 0;
}
函数模板作为类的友元
class A
{
int v;
public:
A(int n) : v(n)
{
}
template<class T>
friend void Print(const T &p);
};
template<class T>
void Print(const T &p)
{
cout << p.v;
}
int main()
{
A a(4);
Print(a);
return 0;
}
/*所有从template
friend void Print(const T &p);生成的函数,都成为A的友元
但是自己写的函数void Print(const T &p){}
不会称为A的友元*/
类模板作为类模板的友元
template<class T>
class B
{
T v;
public:
B(T n) : v(n)
{
}
template<class T2>
friend
class A;
};
template<class T>
class A
{
public:
void Func()
{
B<int> o(10);
cout << o.v << endl;
}
};
int main()
{
A<double> a;
a.Func();
return 0;
}
/* A类,成了B类的友元
任何从A模板实例化出来的类,都是任何B实例化出来的类的友元*/
类模板中可以定义静态成员,那么从该类模板实例化得到的所有类,都包含同样的静态成员
template<class T>
class A
{
private:
static int count;
public:
A()
{
count++; }
~A()
{
count--; }
A(A &)
{
count++; }
static void PrintCount()
{
cout << count << endl; }
};
template<> int A<int>::count = 0;
template<> int A<double>::count = 0;
int main()
{
A<int> ia;
A<double> da;
ia.PrintCount();
da.PrintCount();
return 0;
}
若一个类重载了运算符“()”,则该类的对象就成为函数对象
class CMyAverage
{
//函数对象类
public:
double operator()(int a1, int a2, int a3)
{
return (double) (a1 + a2 + a3) / 3;
}
};
CMyAverage average;//函数对象
cout << average(3,2,3);//average.operator()(3,2,3)