类中的函数是可以访问类中的成员的
#include <iostream>
using namespace std;
class Circle//定义一个Circle 类
{
public:
Circle();//声明一个构造函数
void output();
static double GetD()
{
return D;
}
private:
double radius;//圆的半径
double fruit;//圆的面积
static double D ;
};
double Circle::D = 3.14;
Circle::Circle():radius(0),fruit(0)
{
cout<<"请输入圆的半径:";
cin>>radius;
}
void Circle:: output()
{
double count = GetD();
fruit = count*radius*radius;
cout<<"半径为"<<radius<<"的圆的面积为:"<<fruit<<endl;
}
int main()
{
Circle circle;
circle.output();
cout << "Hello world!" << endl;
return 0;
}
#include<iostream>
using namespace std;
#define D 3.14
class Circle
{
public:
Circle(double Radius);
void output()const;
private:
double radius;
double fruit;
};
Circle::Circle(double Radius)
{
radius=Radius;
fruit=D*radius*radius;
}
void Circle::output()const
{
cout<<"The radius is:"<<radius<<"\tThe fruit is:"<<fruit<<endl;
}
int main()
{
double count;
cout<<"Please input the radius:";
cin>>count;
Circle circle(count);
circle.output();
return 0;
}
变量名实际上是一块内存空间的编号,为变量赋值就是往内存空间放值。c++中的引用可以
对一块内存空间另取别名,格式为type&变量名。相当于type*const
指针变量(指针常量),他占的字节与type无关,相当于指针变量所占的内存。
#include<iostream>
using namespace std;
int main()
{
int a=10;
int &b=a;//引用的举例
cout<<"b="<<b<<" a="<<a<<endl; //10,10
return 0;
}
namespace的含义
#include<iostream>
using namespace std;
namespace namespace1//namespace是一个关键字,std这个命名空间类似一个类,其中有cin,cout,endl
{
int a=10;
}
int main()
{
//using namespace namespace1;
cout<<"a的值为:"<<namespace1::a<<endl; //10
return 0;
}
#include<iostream>
using namespace std;
struct Acounts
{
char id[10];
char password[10];
};
void output(const struct Acounts &my)//void output(struct Acounts*my) 对结构体变量acount 引用
{
cout<<my.id<<endl;
cout<<my.password<<endl;
}
int main()
{
struct Acounts acount;
cin>>acount.id>>acount.password;
output(acount);//output(&acount);
}
指针常量和常量指针
#include<iostream>
using namespace std;
int& modify()//引用作为函数返回值,相当于int*const modify().
{
int c;
cin>>c;
return c;
}
int main()
{
int a = 0;
cout<<modify()<<endl;
cout<<a<<endl;
return 0;
}
#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
int a=3,b=5;
const int*point1=&a; //常量指针
*point1=4;//const tape*指针变量这样表示该指
针所指向存储单元地址的内容不可以被修改
int *const point2=&a; //指针常量
//point2=&b;指针变量的值(地址编号)不能变
tape*const 变量名表示指针指向变量的地址不能变。
const tape*const 变量名表示两者都不能变。
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
return 0;
system("pause");
}
#include<iostream>
using namespace std;
#define COUNT 4
#define d 3.14
class Circle//定义一个圆类
{
public:
void get_r();//成员函数的声明
void output_s();
private:
double my_r;
double my_s;
};
void Circle::get_r()
{
cout<<"请输入半径:";
cin>>my_r;
}
void Circle::output_s()
{
my_s=d*my_r*my_r;
cout<<"半径为"<<my_r<<"的圆的面积为:"<<my_s<<endl;
}
int main()
{
Circle circle[COUNT];定义对象数组
int i;
for(i=0;i<COUNT;i++)
{
circle[i].get_r();//对象调用成员函数
circle[i].output_s();//对象调用成员函数
}
}
设计一个圆类和点类,用面向对象的方法判断圆和点的关系(点在圆内还是圆外)
#include<iostream>
using namespace std;
class Point//定义一个点类
{
public:
Point(double x2,double y2)
{
x0=x2;
y0=y2;
}
int get_x0()const//此成员函数为类中对象访问控制属性为private的数据成员。
{
return x0;
}
int get_y0()const//与上同
{
return y0;
}
private:
double x0,y0;//点的坐标x0,y0.
};
class Circle//定义一个圆类
{
public:
Circle(double x1,double y1,double d1)
{
x=x1;
y=y1;
d=d1;
}
int judge(const Point&mypoint)
{
int dd=(x-mypoint.get_x0())*(x-mypoint.get_x0())+(y-mypoint.get_y0())*(y-mypoint.get_y0());
if(dd<=d*d)
{
return 1;
}
else if(dd>d*d)
return 0;
return 0;
}
private:
double x,y,d;//圆的半径和圆心坐标
};
int main()
{ double x1,y1,d1,x2,y2;
cout<<"请设计一个圆:"<<endl;
cout<<"圆的半径为:";
cin>>d1;
cout<<"圆的圆心坐标X为:";
cin>>x1;
cout<<"圆的圆心坐标y为:";
cin>>y1;
cout<<"点的坐标x为:";
cin>>x2;
cout<<"点的坐标y为:";
cin>>y2;
Circle circle(x1,y1,d1);
Point point(x2,y2);
int flag=circle.judge( point);
if(flag==1)
{
cout<<"点在圆上!";
}
else
cout<<"点在圆外!";
return 0;
}
作业:
- 定义一个point类,其属性包括点的坐标,提供计算两点之间距离的方法
#include<iostream>
#include<cmath>
using namespace std;
class Point
{
public:
void calc_dis();
Point(double x0,double x1,double y0,double y1)
{
x=x0;
x3=x1;
y3=y1;
y=y0;
}
private:
double x,y,dis,x3,y3;
};
void Point::calc_dis()
{
double disdis=(x-x3)*(x-x3)+(y-y3)*(y-y3);
dis=sqrt( disdis);
cout<<"两点间的距离为:"<<dis<<endl;
}
int main()
{ double x,y,x3,y3;
cout<<"请输入点1的坐标x:";
cin>>x;
cout<<"请输入点1的坐标y:";
cin>>y;
cout<<"请输入点2的坐标x3:";
cin>>x3;
cout<<"请输入点2的坐标y3:";
cin>>y3;
Point point(x,x3,y,y3);
point.calc_dis();
return 0;
}
拷贝构造函数的使用:类中的一个对象为另一个对象初始化。
//3.创建两个圆形对象,提示用户输入圆心坐标和半径,判断是否相交
#include<iostream>
#include<math.h>
using namespace std;
class Circle//定义一个圆类
{
public:
void judge(const Circle&my_circle1);
Circle(double x1,double y1,double d1);
Circle(Circle&my_circle);//引用的用法,为对象circle1取别名。拷贝构造函数的用法
private:
double x,y,d;//圆心坐标和半径
};
Circle::Circle(double x1,double y1,double d1)
{
x=x1;
y=y1;
d=d1;
}
Circle::Circle(Circle&my_circle)
{
x=3+my_circle.x;
y=3+my_circle.y;
d=2+my_circle.d;
cout<<"圆2的坐标X2为:"<<x<<endl;
cout<<"圆2的坐标y2为:"<<y<<endl;
cout<<"圆2的半径d2为:"<<d<<endl;
}
void Circle ::judge(Circle&my_circle1)
{
double dis,disdis;//两圆之间的距离和距离的平方
disdis=(x-my_circle1.x)*(x-my_circle1.x)+(y-my_circle1.y)*(y-my_circle1.y);
dis=sqrt(disdis);//sqrt函数在头文件<math.h>中定义,用来求平方根。
if(dis>d+my_circle1.d)
{
cout<<"两圆不相交!"<<endl;
}
else
cout<<"两圆相交!"<<endl;
}
int main ()
{
double x1,y1,d1;
cout<<"请输入圆1的坐标x1:";
cin>>x1;
cout<<"请输入圆1的坐标y1:";
cin>>y1;
cout<<"请输入圆1的半径d1:";
cin>>d1;
Circle circle1(x1,y1,d1);
//Circle circle1=Circle(x1,y1,d1);
Circle circle2(circle1);//利用对象circle1为对象circle2初始化,也可以写成Circle circle2=circle1;
circle1.judge(circle2);
return 0;
}
//4.设计并测试一个名为Rectangle的类,其属性为矩形左下角和右上角的坐标,计算面积
#include<iostream>
using namespace std;
class Rectangle//定义一个Rectangle类
{
public:
Rectangle(double x2,double x3,double y2,double y3)
{
x0=x2;
x1=x3;
y0=y2;
y1=y3;
}
~Rectangle()//析构函数
{
cout<<"析构函数调用!"<<endl;
}
void output();
private:
double x0,x1,y0,y1,s;
};
void Rectangle::output()
{
s=(x1-x0)*(y1-y0);
cout<<"矩形的面积为:"<<s<<endl;
}
int main()
{
double x2,x3,y2,y3;
cout<<"请输入矩形左下角点的坐标x2:";
cin>>x2;
cout<<"请输入矩形左下角点的坐标y2:";
cin>>y2;
cout<<"请输入矩形右上角点的坐标x3:";
cin>>x3;
cout<<"请输入矩形右上角点的坐标y3:";
cin>>y3;
Rectangle rectangle(x2,x3,y2,y3);
rectangle.output();
return 0;
}
对象的动态建立和释放(new和delete运算符的应用)
new类似于c语言中的函数malloc,其基本用法:
- type*指针变量名=new type;
- type*指针变量名=new type(初始值);表示开辟一个数据类型为type的存储空间,并在存储空间里存放这个初始值,运算符new返回存储空间的地址。
- type*指针变量名=new type[元素个数];这里没有数组名。可以定义长度为0的动态数组
int *ptr = new int[0]();
cout << *ptr << endl; //0
cout << &ptr << endl; //0x6dfeec
定位new运算符::允许向new传递额外的参数。例如int *p = new(nothrow)int(0);
表示new不抛出异常
delete类似于c语言中的函数free,其基本用法:
- delete 指针变量名;
- delete []指针变量名;
#include<iostream>
using namespace std;
class Point//定义一个点类
{
public:
Point(double x1)
{
x=x1;
cout<<"x:"<<x<<endl;
}
private:
double x;
};
int main()
{
int *p=new int ;
*p=5;
cout<<*p<<endl;
delete p;
p=new int(10);
cout<<*p<<endl;
delete p;
int*p1=new int [3];
p1[0]=1;
cout<<*p1<<endl;
delete []p1;
Point *p2=new Point(2);//为类这个数据类型开辟一个存储空间
delete (p2);
return 0;
}
当我们希望同类中的多个对象访问一个共有数据成员的属性时,
就可以将这个数据成员用关键字static声明为静态的数据成员,
然后可以用关键字static声明和定义静态成员函数来使用静态的
数据成员。
实际上在对象调用普通成员函数的时候,系统
生成一个this指针。例如在count 这个对象调用
构造函数这个成员函数的时候,等价于Count(Count*const this,int a1)
#include<iostream>
using namespace std;
class Count//定义一个Count类
{
public:
Count(int a1)
{
a=a1;
}
void print()const//const的作用为让this指针指向的对象的数据成员只具有可读性
{
//this->a=12;
cout<<"a:"<<a<<endl;
}
private:
int a;
};
int main()
{
int a1;
cin>>a1;
Count count(a1);
count.print();
return 0;
}
当我们希望某个对象中的私有成员不被修改时就可以在定义普通成员函数的最后加上const这个关键字,即相当于定义了一个常量指针。表示const类名*this
.this指针指向变量的地址的内容是只读的。
利用关键字friend在一个类中声明友元函数,则这个函数可以访问这个类中私有成员的属性,友元函数的作用会破坏类的封装性。
- 使用友元函数来求两点间的距离
#include<iostream>
#include<math.h>
using namespace std;
class Point//定义一个Point类
{
public:
friend void cal(Point&p1,Point&p2);//友元函数的声明
Point(double x1,double y1);
Point(Point&obj);
private:
double x,y;//点的坐标x,y.
};
Point::Point(double x1,double y1)
{
x=x1;
y=y1;
}
Point::Point(Point&obj)
{
this->x=obj.x+1;
this->y=obj.y+1;
}
void cal(Point&p1,Point&p2)
{
double xx=(p1.x-p2.x)*(p1.x-p2.x);
double yy=(p1.y-p2.y)*(p1.y-p2.y);
double dis=sqrt(xx+yy);//dis为两点间的距离
cout<<"两点间的距离为:"<<dis<<endl;
}
int main()
{
double x1,y1;
cout<<"请输入点的坐标x1:";
cin>>x1;
cout<<"请输入点的坐标y1:";
cin>>y1;
Point point1 (x1,y1);
Point point2(point1);
cal(point1,point2);
return 0;
}
类中的成员函数与全局友元函数的区别.友元函数可以不通过类定义的对象来调用,而是可以在类外直接调用。
#include<iostream>
#include<string.h>
using namespace std;
class String//定义一个String类
{
public:
void print_string();
String(const char*p1);
String(String&obj);
private:
char*p;//定义一个指向char型类型的指针
int string_lengh;//定义所需要分配内存单元的长度
friend void print_string(String&string);
};
String::String(const char*p1)
{
this->string_lengh=strlen(p1);
p1=new char[string_lengh+1];
strcpy(p,p1);
}
void String::print_string()
{
cout<<p<<endl;
cout<<"字符串的长度为:"<<string_lengh<<endl;
}
//全局友元函数来实现
void print_string(String&string)
{
cout<<string.p<<endl;
cout<<"字符串的长度为:"<<string.string_lengh<<endl;
}
String::String(String&obj)
{
string_lengh=obj.string_lengh+10;
this->p=new char[string_lengh];
p=obj.p;
}
int main()
{
String string1("hello world");
string1.print_string();
//print_string(string1);
//String string2=string1;//相当于String string2(string1);
//string2.print_string();
return 0;
}
运算符重载的两种实现方法:
- 通过类中的成员函数来实现
- 通过友元函数来实现
根据操作数的个数将运算符重载的方式分为:
- 常用一元运算符重载:++(前置和后置),--(前置和后置),[]
- 常用二元运算符重载:<<,>>,+,-,*,/,==,!=
引用的总结:
- 引用的概念:对一个变量的存储空间地址的编号取别名
- 引用分为内置类型变量的引用和自定义类型的引用
//普通变量的引用:type&变量名2=变量名1
#include<iostream>
using namespace std;
int main()
{
int a=100;
int &b=a;//表示普通变量a和b的地址是一样的,这块地址有两个‘外号’
cout<<"a:"<<a<<endl;
cout<<"b:"<<b<<endl;
return 0;
}
//引用作为函数参数
#include<iostream>
using namespace std;
int swap(int &a,int &b);
int main()
{
int x=10,y=20;
swap(x,y);
cout<<x<<endl;
cout<<y<<endl;
return 0;
}
int swap(int &a,int &b)
{
int c;
c=a;
a=b;
b=c;
return 0;
}
//函数返回值做引用。函数引用的实质:返回变量本身,而不是一个值。
#include <iostream>
using namespace std;
int& func()
{
//堆上分配一块空间
int* p = new int(100);
cout << p << endl;
return *p;
}
int main()
{
int val = func();
cout << val << endl; //100
return 0;
}
//指针变量的引用
#include<iostream>
using namespace std;
int swap( int *&obj)//obj这个变量就是p的别名
{
int c=20;
obj=&c;
return *obj;
}
int main()
{
int a=10;
int *p=&a;
*p=swap(p);
cout<< *p << a << endl; //2020
return 0;
}
常引用: 当我们希望一个引用的变量作为形参不能修改实参变量
的值时,可以在引用变量的数据类型的前面加const)
#include<iostream>
using namespace std;
int main()
{
int a =10;
const int&b = a;//让变量b只拥有只读属性
//b=20;
cout<<b<<endl;
return 0;
}
判断类的继承方式对子类对外访问属性的方法
- 先看调用语句是在子类内还是子类外
- 看子类如何从父类继承
- 看父类中的访问级别
实现多态性的三个步骤:
- 要有继承
- 要有虚函数
- 需要有父类指针或者父类的引用指向子类的不同对象。一般的成员函数加上关键字virtual都可以实现多态性,包括析构函数,但是构造函数不可以。实现多态性的原理:在用类定义一个对象时,编译器会生成一个指向虚函数表的指针,即vptr指针
//实现多态的一个简单案例
#include<iostream>
using namespace std;
class Arm//定义一个Arm类
{
public:
Arm(double val1)
{
this->value1=val1;
cout<<"A"<<endl;
}
virtual int FightValue()
{
return value1;//返回战斗值
}
private:
double value1;
};
class Navy:public Arm//定义一个Navy类,继承于Arm
{
public:
Navy(double val2,double val1):Arm(val1)
{
this->value2=val2;
cout<<"N"<<endl;
}
virtual int FightValue()
{
return value2;
}
private:
double value2;
};
class Enemy//定义一个Enemy类
{
public:
int attack()
{
return value3;
}
Enemy(double value)
{
this->value3=value;
}
private:
double value3;
};
void pk(Arm*point1,Enemy*point2)
{
if(point1->FightValue()>point2->attack())
{
cout<<"我方胜利了!"<<endl;
}
else
cout<<"我方战败了!"<<endl;
}
int main()
{
Navy navy(200,0);//用派生类的子对象为本类和父类的数据成员初始化
Enemy enemy(150);
Arm arm(100);
pk(&navy,&enemy);
pk(&arm,&enemy);
return 0;
}
//父类指针根据传送的不同对象来调用相应对象的成员函数。
重载和重写和重定义的区别:
- 重载:只能发生在同类之间,不同类之间不能发生重载,否则发生同名函数的覆盖
- 重写:多个同名函数利用virtual关键字实现虚函数重写(不同类之间)
- 重定义:不加virtual关键字的同名函数出现在不同类(非虚函数重写)
抽象类的概念:当在一个类中包含有纯虚函数(在类中不执行具体的操作),那么这个类叫做抽象类。纯虚函数即没有定义的虚函数
//抽象类编程的案例
//由点类派生出圆类和矩形类,并求面积
#include<iostream>
#define D 3.14
using namespace std;
class Point
{
public:
virtual int CalArea()=0;//声明一个纯虚函数
Point(double x,double y)//定义一个构造函数
{
this->x=x;
this->y=y;
}
virtual ~Point()//纯虚构函数的定义
{
x=0;
y=0;
cout<<"P";
}
protected:
double x,y;//定义一个点的坐标
};
class Circle:public Point//定义一个圆类
{
public:
virtual int CalArea()
{
s=D*r*r;
return s;
}
Circle(double x,double y,double r):Point(x,y)
{
this->r=r;
}
virtual ~Circle()
{
r=0;
s=0;
cout<<"C";
}
private:
double s,r;//定义面积和半径
};
class Rec:public Point//定义一个长方形类
{
public:
Rec(double x,double y,double x1,double y1):Point(x,y)
{
this->x1=x1;
this->y1=y1;
}
int CalArea()
{
s=(x1-x)*(y1-y);
return s;
}
~Rec()
{
s=0;
x1=0;
y1=0;
cout<<"R";
}
private:
double s;
double x1,y1;//一个点的坐标
};
void Cal(Point* p)
{
cout<<"面积为:"<<p->CalArea()<<endl;
}
void ObjPlay()
{
Circle cir(2,4,3.0);
Rec rec(1,2,3,4);
Cal(&cir);
Cal(&rec);
}
int main()
{
ObjPlay();
return 0;
}
数组类型的基本语法(3种):
#include<iostream>
using namespace std;
int main()
{
typedef int (String)[10];//1.利用宏定义来定义一个数组类型
String string;//数组类型定义变量,相当于int string[10];
string[0]=1;
cout<<string[0]<<endl; //1
typedef int(*Ptr)[10];//2.利用宏定义来定义一个指针数组类型
Ptr ptr;//指针数组类型来定义,相当于int*ptr[10];
ptr=&string;
*ptr[0]=10;
cout<<string[0]<<endl; //10
//3.第三种直接定义一个指针数组类型
return 0;
}
//指针数组类型的基本语法
#include<iostream>
using namespace std;
int Add(int a,int b);
int Add(int a,int b)//1.函数直接调用
{
return a + b;
}
int main()
{
cout<<Add(3,5)<<endl; //8
//2.定义一个函数类型
typedef int(Function)(int a,int b);//宏定义一个函数类型
Function * fun1;//利用函数类型定义一个指针变量
fun1 = &Add;//利用指针间接调用函数Add();
cout<<fun1(3,5)<<endl; //8
//3.定义一个函数指针类型
typedef int(*Func)(int a,int b);
Func func;//利用函数指针类型定义一个指针。
func =Add;
cout<<func(3,5)<<endl; //8
//4.直接定义一个函数指针变量
int (*Fun)(int a,int b);//定义指针变量,带括号表示指向函数的指针变量
Fun = &Add;
cout<<Fun(3,5)<<endl; //8
return 0;
}
//函数指针做函数参数的案例
#include <iostream>
using namespace std;
typedef int (*Ptr)(int a,int b);
int (*Ptd)(int a,int b);
Ptr p = NULL;
// p = Add;
int Fun1(Ptr p);
int Add(int a,int b)
{
return a + b;
}
int Fun1(Ptr p)//函数指针做函数参数来间接调用
{
int c=p(2,3);
return c;
}
int Fun2(int (*Ptd)(int a,int b))
{
int c = ptd(3,5);
return c;
}
int main()
{
//cout<<Add(2,3)<<endl;//函数的直接调用
//Ptr ptr;//利用宏定义的函数指针类型来定义一个函数指针
//cout<<ptr(2,3)<<endl;//函数的间接调用
//Fun1(Add);
cout<<Fun1(Add)<<endl;
cout<<Fun2(Add)<<endl;
return 0;
}
//利用函数模板泛型编程对字符串和整形数组进行排序
#include <iostream>
using namespace std;
template<typename T1,typename T2>
int Sort(T1 *str,T2 size)//注意数据类型,第一个参数为指针类型,第二个为整形
{
int i,j;
T2 tempt;
for(i=0;i<size;i++)
{
for(j=1+i;j<size;j++)
{
if(str[i]<str[j])
{
tempt=str[j];
str[j]=str[i];
str[i]=tempt;
}
}
}
return 0;
}
template<typename T1,typename T2>
int MyPrint(T1*string1,T2 size)
{
T2 i;
cout<<"排序后:";
for(i=0;i<size;i++)
{
cout<<string1[i]<<" ";
}
return 0;
}
int main()
{
int str[]={21,4,67,34,5,6};
char array[]="aedartgvsedft";
int lengh =sizeof(str)/sizeof(int);
int lengh1=sizeof(array)/sizeof(char);
//cout<<lengh<<endl;
Sort<int,int>(str,lengh);
MyPrint<int,int>(str,lengh);
Sort<char,int>(array,lengh1);
MyPrint<char,int>(array,lengh1);
return 0;
}
简单类模板泛型编程的案例
#include <iostream>
using namespace std;
template<typename T>
class Parent
{
public:
Parent(T a=0)//默认参数 a=0
{
this->a=a;
}
protected:
T a;
};
template<typename T>
class Son:public Parent<T>//父类模板派生出子类模板
{
public:
void MyPrint()
{
cout<<"b:"<<b<<endl;
}
Son(T a,T b):Parent <T>(a)
{
this->b=b;
}
private:
T b;
};
int main()
{
Son <int>son(3,5);
son.MyPrint();
return 0;
}
将类模板的成员函数的声明和实现分开的案例
#include <iostream>
using namespace std;
template<typename T>
class Parent
{
public:
Parent(T a);
void MyPrint();
private:
T a;
};
template<typename T>
Parent<T>::Parent(T a)
{
this->a=a;
}
template<typename T>
void Parent<T>::MyPrint()
{
cout<<"a:"<<a<<endl;
}
int main()
{
//Parent <int>par(100);
Parent <char>par('a');
par.MyPrint();
return 0;
}
编程题
- 编写函数模板,实现求对有n个元素的数组X[n]求最大值
#include <iostream>
using namespace std;
template <typename T1,typename T2>
void printMax(T1* p,T2 length)
{
T1 temp;
for(int i = 1; i < length; i++)
{
if(p[i] > p[0])
{
temp = p[i];
p[i] = p[0];
p[0] = temp;
}
}
// printf("最大值为:%d\n",p[0]);
cout << "最大值为:" << p[0] << endl;
}
int main()
{
int arr[] = {12,25,1111,59,250};
printMax<int,int>(arr,sizeof(arr) / sizeof(int)); //1111
char str[] = {"ars define"};
printMax<char,int>(str,sizeof(str) / sizeof(char)); //s
return 0;
}
//2. 设计一个数组类模板,通过定义成员函数实现对数组排序,查找和求元素和的运算
#include<iostream>
#define COUNT 10
using namespace std;
template <typename T>
class Model
{
public:
void Sort(Model<T>&obj1);//声明排序函数
void Sum(Model<T>&obj1);//声明求和函数
Model(int size);//声明构造函数
T& Find(int index);//声明查找元素的函数
int GetLengh()
{
return lengh;
}
T& operator [](int ind);//声明重载下标运算符函数
~ Model()
{
if(space!=NULL)
{
delete []space;
//space==NULL;
lengh=0;
}
}
protected:
int lengh;//数组长度
T *space;
};
template <typename T>
void Model<T>::Sort(Model<T>&obj)
{
int i,j;
T tempt;
for(i=0;i<obj.lengh - 1;i++)
{
for(j=i+1;j<obj.lengh;j++)
{
if(obj[i]<obj[j])
{
tempt=obj[i];
obj[i]=obj[j];
obj[j]=tempt;
}
}
}
cout<<"排序后:"<<endl;
for(int i=0;i<obj.GetLengh();i++)
{
cout<<obj[i]<<" ";
}
cout<<endl;
}
template <typename T>
void Model<T>::Sum(Model<T>&obj1)
{
T sum=0;
for(int i=0;i<obj1.lengh;i++)
{
sum+=obj1[i];
}
cout<<"和为:"<<sum<<endl;
}
template <typename T>
T& Model<T>::Find(int index)
{
cout<<space[index-1]<<endl;
return space[index-1];
}
template <typename T>
Model<T>::Model(int size)
{
this->lengh=size;
space=new T[lengh];
}
template <typename T>
T&Model<T>:: operator [](int ind)//重载下标操作符
{
return space[ind];
}
int ObjPlay()
{
int ind;//需要查找元素的序号
Model<int>mod1(COUNT);
cout<<"排序前:"<<endl;
for(int i=0;i<mod1.GetLengh();i++)
{
mod1[i]=i+1;
cout<<mod1[i]<<" ";
}
cout<<endl;
mod1.Sort(mod1);
cout<<"请输入你想查找元素的标号:";
cin>>ind;
if(ind<=0||ind>COUNT)
{
cout<<"请输入有效的元素序号!"<<endl;
return -1;
}
mod1.Find(ind);
mod1.Sum(mod1);
return 0;
}
int main()
{
ObjPlay();
return 0;
}
//C++中的强制类型转换(4种)
#include<iostream>
using namespace std;
int main()
{
double a = 3.24;
//1.static_cast<a>(b);a为强制转换后的数据类型,b为需要强制转换的变量名
int b = static_cast<int>(a);//静态类型转换,c++编译器会进行类型检查
cout<<"a:"<<a<<" b"<<b<<endl;
//2.reinterpreter_cast<a>(b);与上面同
char *p1="helloworld";
int *p2=reinterpret_cast<int*>(p1);
cout<<"p1:"<<p1<<" p2:"<<p2<<endl;
return 0;
}
//3.dynamic_cast<>();
//4.const_cast<>();去除只读属性
异常处理的基本语法:
- 检查异常(try语句块)
- 抛出异常(throw语句块)
- 捕捉并处理异常(catch语句块)
注意:try语句块必须和catch语句块相连,之间不能有其他的句子。
#include<iostream>
using namespace std;
void MyCopy(char *p1,char *p2)
{
if(p2==NULL)
{
throw 1;//throw可以抛出字符串,类的对象,普通数据类型的变量或者表达式
cout<<"源buf出错!";
}
if(p1==NULL)
{
throw 2;
cout<<"目的buf出错!";
}
if(*p2=='a')
{
throw "首字母出错";
}
while(*p2!='\0')
{
*p1=*p2;
p1++;
p2++;
}
*p1='\0';
}
int main()
{
char buf1 []="lewdrtyhgj";
char buf2 [1024]={0};
try
{
MyCopy(buf2,buf1);
}
catch(int e)
{
cout<<e<<"int类型出错"<<endl;
}
catch(char*e)
{
cout<<*e<<"char*类型出错"<<endl;
}
catch(...)
{
cout<<"未知类型出错"<<endl;
}
cout<<buf2<<endl;
cout<<"HelloWorld"<<endl;
return 0;
}
新建一个文件,并且写入一串数据
#include<iostream>
using namespace std;
#include<fstream>//fstream这个流类继承于iostream这个流类
int main()
{
ofstream outl;//ofstream流类继承于ostream类
outl.open("e:\\a.txt",ios::out);//输入输出方式在虚基类ios中定义的枚举常量
if(!outl)//如果用构造函数打开文件失败,则流对象的值为0.
{
cout<<"文件打开失败!"<<endl;
return ;
}
outl<<"helloworld";
outl.close();
ifstream inl;//文件输入流类定义一个对象
inl.open("e:\\a.txt",ios::in);
if(!inl)
{
cout<<"文件打开失败!"<<endl;
return ;
}
char ch;
while(inl.get(ch))//get函数的作用为从输入流中读取一个字符并且存入字符变量ch中
{
cout<<ch;
}
cout<<endl;
inl.close();
return 0;
}
打开一个存放于e盘的文件,并且添加数据
#include<iostream>
#include<fstream>
#include <cstring>
using namespace std;
int main()
{
ofstream ofile("e:\\a.txt",ios::app);//nocreate表示打开一个已有的文件,app表示在原有文件的基础上添加数据
if(!ofile)
{
cout<<"File open error!"<<endl;
}
char *p1="I am li",*p2;
ofile.write( p1,strlen(p1));
ofile.close();
ifstream ifile("e:\\a.txt",ios::in);
char ch;
while(ifile.get(ch))
{
cout<<ch;
}
//get函数表示从输入流文件中读取一个字符到内存中
ifile.close();
return 0;
}
//模板类vector:可以往vector里面装载不同数据类型的值
#include<iostream>
using namespace std;
#include<vector>//使用模板类需包含头文件vector
int main()
{
const int count=5;
int i;
vector<int>array(count);//往vector里面放包含5个int类型元素的数组
for( i=0;i<count;i++)
{
array[i]=i;
cout<<array[i]<<" ";
}
return 0;
}
//迭代器iterator:广义上是一个指针,指向容器中的首元素
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int main()
{
const int count=3;
vector <string>::iterator pd;//为vector的string类型声明一个迭代器
vector<string>array(count);//vector 模板类定义对象arry
for(int i=0;i<count;i++)
{
array[i]="hello";
}
pd=array.begin();//begin将返回一个指向string首元素的指针
for(pd=array.begin();pd!=array.end();pd++)
{
cout<<*pd<<" ";
}
cout<<"After erase:"<<endl;
//erase函数的功能删除容器中的元素,其两个参数为要删除的区间
array.erase(array.begin()+1,array.begin()+2);
string str="World";
//push_back函数的功能为向容器中添加元素,
array.push_back(str);
for(pd=array.begin();pd!=array.end();pd++)
{
cout<<*pd<<" ";
}
return 0;
}
sort函数(不是某个容器的成员函数)可以对容器中的矢量进行排序,要求该容器可以随机访问
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int>array(4);
array[0]=1;
array[1]=5;
array[2]=2;
array[3]=6;
sort(array.begin(),array.end());
for(int i = 0; i < array.size(); i++)
cout << array[i] << " ";
return 0;
}
对于普通的模板函数,编译器通过隐式实例化来使用模板生成函数定义
下面是另外一种显示实例化
#include<iostream>
using namespace std;
int main()
{
int a=3;
//decltype:一个关键字用于获取资源的类型
decltype(a)b=5;
cout<<b<<endl;
return 0;
}
//本编译器不支持
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char*p = new char[1024],*p1="HelloWorld";
strcpy(p,p1);
cout<<p<<endl;
//system("pause");
return 0;
}
依据变量的单定义规则,变量只能被定义一次。如果要在多个文件中使用同一个变量,则只要在一个文件中包含该变量的定义,在使用该变量的其他文件中必须使用关键字extern来声明.
#include<iostream>
#include<string.h>
int main()
{
char *p2="World";
int lengh=strlen(p2);
char*p1=new char[lengh+1];
strcpy(p1,p2);
std::cout<<p1<<std::endl;
delete []p1;
return 0;
}
利用oop来表示ADT(抽象数据类型)比如栈
#include<iostream>
using namespace std;
class stack
{
private:
enum{num=10};
int top;//声明一个栈顶指针
int item[num];
public:
bool IsEmp()const;//const表示不允许函数通过this指针修改对象中的数据成员
bool IsFul()const;
int pop();
int push(int b);
stack()
{
top=0;
}
};
bool stack::IsFul()const
{
//cout<<"wo bei diao yong"<<endl;
return top==num;
}
bool stack::IsEmp()const
{
return top==0;
}
int stack:: push(int b)
{
if(IsFul())
{
cout<<"stack is full!"<<endl;
return -1;
}
else
{
item[top]=b;
top++;
}
return b;
}
int stack:: pop()
{
int a;
if(IsEmp())
{
cout<<"stack is empty!"<<endl;
return -2;
}
else
{
top--;
a=item[top];
return a;
}
}
int main()
{
stack sta;
//cout<<sta.IsEmp()<<endl;
//频繁的入栈和出栈
for(int i=0;i<12;i++)
{
sta.push(i);
cout<<sta.pop();
}
return 0;
}
实现两个字符串变量的交换
#include<iostream>
void swap(char*&p1,char*&p2)
{
char*temp;
temp=p1;
p1=p2;
p2=temp;
}
int main()
{
char*ap="hello";
char*bp="how are you";
std::cout<<"交换前"<<ap<<" "<<bp<<std::endl;
swap(ap,bp);
std::cout<<"交换后"<<ap<<" "<<bp<<std::endl;
return 0;
}
//重载常用的+-*/运算符案例.有些运算符可以通过成员函数的方法来重载,也可以通过友元函数来重载
#include<iostream>
using std::cout;
using std::endl;
class Data
{
private:
int x,y;
public:
Data(int x,int y);//有参构造函数
//Data(Data&da);//拷贝构造函数
Data (){x=0;y=0;}//默认构造函数的定义
Data operator +(Data&da);
Data operator *(double x1);
//friend Data operator *(double x,Data&da);
void ShowValue();
};
Data::Data(int x,int y)
{
this->x=x;
this->y=y;
}
Data Data::operator +(Data&da)
{
Data temp;
temp.x=this->x+da.x;
temp.y=this->y+da.y;
return temp;
}
Data operator *(double x1,Data&da)
{
Data temp;
temp.x=x1*da.x;
temp.y=x1*da.y;
return temp;
}
*/
/*
Data Data:: operator *(double x1)
{
Data temp;
temp.x=x1*x;
temp.y=x1*y;
return temp;
}
void Data::ShowValue()
{
cout<<"("<<x<<","<<y<<")"<<endl;
}
int main()
{
Data data1(3,5);
Data data2(2,4);
Data data3=data1+data2;//相当于data1. operator +(data2);
//Data data4=4.0*data3;
Data data4=data3*4.0;
data1.ShowValue();
data2.ShowValue();
data3.ShowValue();
data4.ShowValue();
return 0;
}
//重载左移操作符<<
#include<iostream>
//using namespace std;
class Data
{
private:
int x;
public:
Data(int x1=0)
{
x=x1;
}
friend std::ostream& operator <<(std::ostream&os,Data&da);
};
std::ostream& operator <<(std::ostream&os,Data&da)
{
os<<da.x;
return os;
}
int main()
{
Data data1(100),data2(200);
std::cout<<data1<<" "<<data2<<std::endl;//重载左移操作符后可以直接输出用户自定义的数据类型的变量
return 0;
}
//链式编程的探讨
#include<iostream>
class A
{
private:
int x;
public:
A(int x)
{
this->x=x;
}
A()
{
x=0;
}
void show()
{
std::cout<<x<<std::endl;
}
A operator +(const A&i);
};
A A::operator +(const A&i)
{
{
A temp;//建立临时对象需要显示提供默认无参构造函数
temp.x=this->x+i.x;
return temp;
}
//也可以返回一个以构造函数的形式来创建对象的对象的副本
return A(this->x+i.x);
}
int main()
{
A a(100),b(200),c(300);
A d=a+b+c;//链式编程相当于a.operator(b.operator(c))
d.show();
return 0;
}
转换构造函数的使用
- 类型转换:可以通过转换构造函数将其他数据类型转换为类这个数据类型。
- 接受一个参数的构造函数为类型与参数相同的值转化为类这个数据类型。
- 转换函数:属于类中的成员函数,声明格式为operator typename();typename为需要将类这个数据类型转换后的数据类型,转换函数没有返回值和参数。
#include<iostream>
class Data
{
private:
int x;
public:
Data(int x)
{
this->x=x;
}
void show()
{
std::cout<<x<<std::endl;
}
operator double()
{
return double (x);
}
};
int main()
{
Data data=100.5;//先将100.5这个double类型转化为int型,再通过构造函数转化为类型
//Data data(100);
//Data data=Data(100);
data.show();
double x=data;//将类这个数据类型转换为int型,将调用类的转换成员函数
std::cout<<x<<std::endl;
return 0;
}
显示explicit关键字的用法:在只接受一个参数的构造函数前加上该关键字,表示在将其他数据类型转换为类类型时,只能进行显示转换
#include<iostream>
using std::cout;
using std::endl;
class Data
{
public:
explicit Data(int x)
{
this->x=x;
}
~Data()
{
cout<<"destructor calls"<<endl;
}
void show()
{
cout<<x<<endl;
}
private:
int x;
};
int main()
{
//Data data=(Data)3.0;//显示转换
//Data data=3.0隐式转换
Data data(3.0);
data.show();
return 0;
}
//拷贝构造函数用于将一个已经初始化的对象赋给一个新创建的对象
#include<iostream>
using std:: cout;
using std:: endl;
class Data
{
private:
int x;
public:
Data(int x=0)
{
this->x=x;
}
Data(Data&i)
{
this->x=i.x;
}
void show()
{
cout<<x<<endl;
}
};
int main()
{
Data data(100);//相当于Data data=Data(100);
Data da=data;//相当于Data da=Data(data);
da.show();
return 0;
}
将一个已有的类对象初始化一个新创建的对象的两种方法:不能执行第三种方法:将已有的对象直接赋给新建对象,因为会带来深拷贝和浅拷贝的问题。
- 在类中添加拷贝构造方法
- 在类中添加重载等号操作符方法.
如果将一个已有的对象赋给另一个已有的对象,则必须添加重载等号操作符函数。第二种方法的优点:可以不通过拷贝构造函数生成一个临时对象,生成临时对象很可能会调用析构函数.
#include<iostream>
#include<cstring>
using namespace std;
class Data
{
private:
char*p;
int lengh;//用于存储字符串的长度
public:
Data()
{
}
Data(const char*p1);
Data(const Data&da);//拷贝构造函数的声明
~Data();
Data& operator =(Data&da);//重载=操作符的声明
friend ostream & operator <<(ostream&os,Data&da);//重载<<操作符的声明
};
Data::Data(const char*p1)
{
if(p1==NULL)
{
return ;
}
lengh=strlen(p1);
p=new char[lengh+1];
strcpy(p,p1);
}
Data::Data(const Data&da)
{
lengh=da.lengh;
p=new char[lengh+1];
strcpy(p,da.p);
}
Data::~Data()
{
if(p!=NULL)
{
delete p;
}
}
ostream & operator <<(ostream&os,Data&da)
{
os<<da.p;
return os;
}
Data& Data:: operator =(Data&da)
{
if(this==&da)
{
return *this;//检验已创建对象是否通过拷贝构造函数复制成功
}
lengh=da.lengh;
p=new char[lengh+1];
strcpy(p,da.p);
return *this;
}
int main()
{
Data data1("HelloWorld");
//将一个已有对象初始化另一个新建对象
Data data2=data1;//调用拷贝构造
Data data3;
//将一个已有对象赋值给另一个已有对象
data3 = data1; //调用重载的等号方法
cout<<data1<<" "<<data2<<data3<<endl;
return 0;
}
C++中提供了关键字nullptr,表示一个指针变量为空指针,相当于在c语言中定义的宏NULL的值为0;
#include<iostream>
int main()
{
using std::cout;
using std::endl;
int *p=nullptr;
cout<<p<<endl; //0
return 0;
}
new 运算符:
- 常规new运算符:在堆中分配内存
- 定位new运算符:在分配内存的时候指定内存位置使用定位运算符new需要包含头文件new
如果类中的数据成员是非静态const成员或则引用,(非静态的原因是静态的类成员可以直接声明定义或者在类外定义)则使用构造函数进行初始化时,需要使用初始化列表
#include<iostream>
class Data
{
private:
const int count;
public:
Data(int c):count(c)
{
}
Data ():count(0)
{
}
void show()
{
std::cout<<count<<std::endl;
}
};
int main()
{
Data data1;
Data data2(1);
data1.show();
data2.show();
return 0;
}
自定义一个字符串:按照首字母顺序找出字母最大的字符串
#include<iostream>
#include<cstring>
class String
{
private:
int lengh;//字符串长度
char *p;
public:
String()
{
lengh=0;
p=new char[1];
strcpy(p,"\0");
}
String(const char*p1);
~String();
bool operator >(String&str);//重载>操作符
friend std::ostream& operator <<(std::ostream&os,String&str);//重载左移操作符
String operator =(String&str);
};
String::String(const char*p1)
{
if(p1==NULL)//检查是否传来空字符串
{
return;
}
lengh=strlen(p1);//求所传来的字符串
p=new char[lengh+1];//为类中数据成员分配空间
strcpy(p,p1);//拷贝字符串
}
String::~String()
{
if(p!=NULL)
{
delete p;
}
lengh=0;
}
bool String::operator >(String&str)
{
return p>str.p;
}
std::ostream& operator <<(std::ostream&os,String&str)
{
os<<str.p<<std::endl;
return os;
}
String String::operator =(String&str)
{
if(&str == this)
{
return *this;
}
else
{
delete []p;
lengh=str.lengh;
p=new char[lengh+1];
strcpy(p,str.p);
}
return *this;
}
int main()
{
using std::endl;
using std::cout;
const int count=4;
String str[count]={"hello","world","big","smallest"};
//String*ptr=&str[0];
for(int i=0;i<count;i++)
{
if(str[i]>str[0])
str[0]=str[i];
}
cout<<":"<<str[0]<<endl;
return 0;
}
使用虚函数来实现多态性的缺点:
- 程序将使用动态联编的方式,这一方式使得在使用类定义对象为对象分配存储空间时,将增加额外的空间来存储每个对象都有的虚函数表的地址。使用指向对象的指针或者引用调用虚函数时,程序查看对象的虚函数表的地址,然后匹配对应的虚函数的地址。因此c++编译器默认采用静态联编的方式
#include<iostream>
#include<cstring>
class Parent
{
private:
char *p;//4个字节
public:
Parent( const char *p2);
//Parent(Parent&pa);
~Parent();
};
class Son:public Parent
{
private:
int count;//4个字节
public:
Son(int c, const char*p1);
~Son();
};
Parent::Parent( const char *p2)
{
p=new char[sizeof(p2)+1];
strcpy(p,p2);
std::cout<<"construction calls"<<" "<<p<<std::endl;
}
Parent::~Parent()
{
std::cout<<"destruction calls"<<std::endl;
delete []p;
}
Son::Son(int c, const char*p1):Parent(p1)
{
count=c;
}
Son::~Son()
{
std::cout<<"Son calls"<<std::endl;
}
int main()
{
Son son(3,"Hello");
std::cout<<sizeof(son)<<std::endl;//8个字节
return 0;
}
*/
/*
上述案例表明:派生类不管以何种方式继承于基类,都会将基类的全部
数据成员继承过来(不管数据成员在基类中的访问属性如何)。因此在
定义派生类对象时,继承过来的基类数据成员将调用基类的构造函数来
为这些数据成员分配内存,同样调用析构函数来释放这些数据成员的内
存。
*/
#include<iostream>
#include<cstring>
class Data
{
private:
int x;
char *p;
public:
Data(int x,const char *p1)
{
this->x=x;
p=new char[std::strlen(p1)+1];
strcpy(p,p1);
std::cout<<"constructor calls"<<std::endl;
}
Data()
{
std::cout<<"calls"<<std::endl;
x=0;
p=NULL;
}
Data(const Data&da)
{
this->x=da.x;
p=new char[std::strlen(da.p)+1];
strcpy(p,da.p);
}
~Data()
{
std::cout<<"destructor calls"<<std::endl;
x=0;
delete []p;
}
void show()const
{
std::cout<<x<<" "<<p<<std::endl;
}
};
int main()
{
{
Data data1(3,"Hello");
Data data2=data1;
data2.show();
}
return 0;
}
*/
/*
上述案例中:语句Data data2=data1;
先调用拷贝构造函数生成Data1的副本,然后调用编译器生成的
默认的赋值运算符函数,将Data1副本的值赋给Data2;
*/
valarray:c++库提供的一个类,使用这个类时需要包含头文件valarray
#include<iostream>
#include<valarray>
int main()
{
std::valarray<double>val(3,4);//表示4个double类型的数据并都初始化为3
std::cout<<val[3]<<std::endl;
return 0;
}
在类的外面只能通过类的公有方法来访问类的私有成员
#include<iostream>
class Data
{
public:
void show()
{
std::cout<<x<<std::endl;
}
private:
int x;
public:
Data(int x)
{
this->x=x;
}
};
int main()
{
Data da(100);
da.show();
return 0;
}
string类是一个c++库中的一个类,封装了数据和方法
string类的常用操作:定义字符串类型的数据,遍历字符串,拷贝字符串,字符串的替换,连接字符串,删除字符串,插入字符串
#include<iostream>
#include<string>
int main()
{
using std::cout;
using std::endl;
using std::string;
string str="abcdefg";//string类定义对象
string str1("Hello");
cout<<"str1:"<<str1<<endl;
//方法一使用数组的方式进行遍历字符串
for(unsigned int i=0;i<str.length();i++)
{
cout<<str[i]<<" ";
}
cout<<endl;
//方法二使用迭代器的方式进行遍历字符串
for(string::iterator it=str.begin();it!=str.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//类中c_str函数的声明const _CharT*c_str() const
cout<<"str:"<<str.c_str()<<endl;//返回指针
char buff[10]={0};
//在string类中声明的copy函数原型
//copy(_CharT* __s, size_type __n, size_type __pos = 0) const;
str.copy(buff,3,0);//表示从0开始读取3个字符到buff内存中
cout<<buff<<endl;
//类中replace函数的声明basic_string&
//replace(size_type __pos, size_type __n, const basic_string& __str)
str.replace(0,3,"ABC");
cout<<"str:"<<str<<endl;
str.append("hijk");
cout<<"str:"<<str<<endl;
int count=str.find("ABC",0);
cout<<"count:"<<count<<endl;
//删除字符串
str.erase(str.begin(),str.end());
cout<<":"<<str<<endl;
str1.insert(1,"ABC",2);//从1号位置开始插入中间字符串的两个字节数据
cout<<"str1:"<<str1<<endl;
str1.insert(0,"AAA");//头插法
str1.insert(str1.length(),"CCC");//尾插法
cout<<"str1:"<<str1<<endl;
return 0;
}
C++中的vector容器类的常用操作
#include<iostream>
#include<vector>
int main()
{
using std:: endl;
using std:: cout;
using std::vector;
vector<int>vec;
cout<<vec.size();//求vector这个矢量容器的大小
vec.push_back(1);//往vector这个矢量容器添加元素
vec.push_back(3);
vec.push_back(5);
//声明vector类的一个迭代器的一种方式(有多种方式)
//顺序输出数组中的元素
for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//声明迭代器的另一种方式
//逆序输出数组中的元素
for(vector<int>::reverse_iterator it=vec.rbegin();it!=vec.rend();it++)
{
cout<<*it<<" ";
}
cout<<endl;
vec.front()=10;//修改数组首部的首元素
vec.back()=100;//修改数组首部的尾元素
for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
vec.pop_back();//删除尾部元素
for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//删除vector容器指定区间的元素
vec.erase(vec.begin(),vec.begin()+2);//表示[0,2)区域
for(unsigned int i=0;i<vec.size();i++)
{
cout<<vec[i]<<" ";
}
cout<<endl;
vec.push_back(1);//往vector这个矢量容器添加元素
vec.push_back(3);
vec.push_back(5);
vec.push_back(1);
vec.push_back(1);
//删除vector容器指定元素的值
for(vector<int>::iterator it=vec.begin();it!=vec.end();)
{
if(*it==1)
{
it=vec.erase(it);//先删除迭代器指定位置的值,然后迭代器指针
//自动指向下一元素的地址,然后将此地址赋给迭代器指针
}
else
it++;
}
for(unsigned int i=0;i<vec.size();i++)
{
cout<<vec[i]<<" ";
}
cout<<endl;
vec.clear();
for(unsigned int i=0;i<vec.size();i++)
{
cout<<vec[i]<<" ";
}
return 0;
}
c++中的deque容器类:双端数组容器类的常用操作
#include<iostream>
#include<deque>
using std::endl;
using std::cout;
using std::deque;
void MyPrint(deque<int>&d)
{
for(unsigned int i=0;i<d.size();i++)
{
cout<<d[i]<<"";
}
cout<<endl;
}
int main()
{
deque<int>de(5);
de.push_back(1);
de.push_back(3);
de.push_back(5);
de.push_back(7);
de.push_back(9);
MyPrint(de);
de.pop_front();//删除双端数组容器首部的元素
de.push_front(100);//往该容器添加首部元素
MyPrint(de);
return 0;
}
c++中的stack容器类的相关操作
#include<iostream>
#include<stack>
int main()
{
using std::endl;
using std::cout;
using std::stack;
stack<int>sta;
cout<<sta.size()<<endl;
for(unsigned int i=0;i<10;i++)
{
sta.push(i+1);//入栈操作
}
while(!sta.empty())
{
cout<<sta.top()<<" ";//打印栈顶元素
sta.pop();//类似栈顶指针下移
}
return 0;
}
C++中的quene容器类的使用(队列)
#include<iostream>
#include<queue>
class Teacher
{
private:
int x;
public:
void show()
{
std::cout<<x<<" ";
}
Teacher(int x)
{
this->x=x;
}
};
int main()
{
using std::queue;
using std::endl;
using std::cout;
queue<int>de;
de.push(100);
de.push(200);
de.push(300);
cout<<"队头元素为:"<<de.front()<<endl;
while(!de.empty())
{
cout<<de.front()<<" ";
de.pop();
}
cout<<endl;
Teacher t1(35),t2(25),t3(45);
queue<Teacher>q;//往queue容器类存放类型的数据元素
q.push(t1);
q.push(t2);
q.push(t3);
while(!q.empty())
{
Teacher tempt=q.front();
tempt.show();
q.pop();
}
return 0;
}
双向链表list容器类的使用(不支持随机存取)
#include<iostream>
#include<list>
int main()
{
using std::list;
using std::cout;
using std::endl;
using std::iterator;
list<double>li;
li.push_front(100);//头插法
li.push_back(300);//尾插法
li.push_front(10);
li.push_front(10);
list<double>::iterator it=li.begin();//声明定义一个list容器的迭代器
while(it!=li.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
//在指定的位置插入元素
list<double>::iterator it1=li.begin();
li.insert(it1,1000);
while(it1!=li.end())
{
cout<<*it1<<" ";
it1++;
}
cout<<endl;
li.remove(10);//删除与10相同的值
it=li.begin();
while(it!=li.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
li.clear();
it=li.begin();
cout<<"清空后:";
while(it!=li.end())
{
cout<<*it<<" ";
it++;
}
return 0;
}
priority_queue容器类的常用操作(最大值优先值序列和最小值优先序列)
#include<iostream>
#include<queue>
int main()
{
using std::cout;
using std::endl;
using std::priority_queue;
priority_queue<int>qu;//默认最大值优先序列,出对的顺序为从大到小
qu.push(100);
qu.push(200);
qu.push(300);
qu.push(400);
cout<<"优先队列的长度为:"<<qu.size()<<endl;
while(!qu.empty())
{
cout<<qu.top()<<" ";
qu.pop();
}
cout<<endl;
return 0;
}
c++中set集合容器的操作,容器特点:元素唯一(默认从小到大),不支持随机存取
#include<iostream>
#include<set>
int main()
{
using std::set;
using std::cout;
using std::endl;
set<int>s;
for(int i;i<10;i++)
{
int tempt=i+0;
s.insert(tempt);
}
s.insert(100);
s.insert(100);
s.insert(100);
set<int>::iterator it=s.begin();
while(it!=s.end())
{
cout<<*it<<" ";
it++;
}
return 0;
}
for_each函数应用于容器中的各个元素,前两个参数是容器区间的迭代器,第三个参数是指向函数的指针或者函数对象。函数不能修改容器里的元素 基于范围的for循环:
#include<iostream>
#include<algorithm>
#include<vector>
using std::vector;
class Data
{
public:
int rating;
Data(int r)
{
rating=r;
}
};
int Show(const Data&ve)
{
std::cout<<ve.rating<<std::endl;
return 0;
}
int main()
{
vector<Data>vec;
Data da1(100),da2(200);
vec.push_back(da1);
vec.push_back(da2);
for_each(vec.begin(),vec.end(),Show);//Show为函数对象
return 0;
}
仿函数(函数对象)的应用,greater
#include<iostream>
#include<set>
int main()
{
using std::set;
using std::cout;
using std::endl;
using std::greater;
using std::less;
set<int,greater<int> >se1;//此处> >有空格
se1.insert(10);
se1.insert(20);
se1.insert(30);
se1.insert(40);
for(set<int,greater<int> >::iterator it=se1.begin();it!=se1.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//set<int,less<int> >se2;//此处> >有空格
set<int>se2;//省略的函数对象默认是less<int>
se2.insert(10);
se2.insert(30);
se2.insert(20);
se2.insert(40);
for(set<int,less<int> >::iterator it=se2.begin();it!=se2.end();it++)
{
cout<<*it<<" ";
}
return 0;
}
set容器的操作;pair对组的应用,pair也是一个类。multset容器操作set容器类似,容器里同一个元素可以不唯一
#include<iostream>
#include<set>
int main()
{
using std::endl;
using std::cout;
using std::set;
set<int>se;
for(int i=0;i<10;i++)
{
se.insert(i+1);
}
set<int>::iterator it=se.find(6);//查找容器中的元素,返回该元素的地址
cout<<"*it:"<<*it<<endl;
int count=se.count(0);//查找容器中的元素的个数
cout<<"count:"<<count<<endl;
it=se.lower_bound(5);//返回大于或者等于某元素的迭代器
cout<<"*it:"<<*it<<endl;
it=se.upper_bound(5);//返回大于某元素的迭代器
cout<<"*it:"<<*it<<endl;
//std::pair<iterator, iterator>equal_range(const key_type& __x)
std::pair<set<int>::iterator,set<int>::iterator>pair1=se.equal_range(6);
set<int>::iterator it1=pair1.first;
cout<<"*it1:"<<*it1<<endl;
set<int>::iterator it2=pair1.second;
cout<<"*it2:"<<*it2<<endl;
return 0;
}
map容器的操作
#include<iostream>
#include<map>
#include<string>
void main1()
{
using std::map;
using std::cout;
using std::endl;
using std::string;
map<int,string>ma;
//容器元素的添加
//方法一
ma.insert(map<int,string>::value_type(1,"teacher1"));
//方法二
ma.insert(std::pair<int,string>(2,"teacher2"));
//方法三.前三种insert方法可以检查插入元素是否成功
//若键值已经存在,则报错
std::pair<map<int,string>::iterator,bool> pair1=ma.insert(std::make_pair(3,"teacher3"));
if(!pair1.second)
{
cout<<"插入元素失败"<<endl;
}
else
cout<<pair1.first->first<<"\t"<<pair1.first->second<<endl;
std::pair<map<int,string>::iterator,bool> pair2=ma.insert(std::make_pair(3,"teacher43"));
if(!pair2.second)
{
cout<<"插入元素失败"<<endl;
}
else
cout<<pair2.first->first<<"\t"<<pair2.first->second<<endl;
//方法四。这种方法不能检查插入元素是否成功
//若键值已经存在,则进行覆盖
ma[4]="teacher4";
ma[4]="teacher44";
//容器元素的遍历
for(map<int,string>::iterator it=ma.begin();it!=ma.end();it++)
{
cout<<it->first<<"\t"<<it->second<<endl;
}
//容器元素的查找iterator find(const key_type& __x)和异常处理
map<int,string>::iterator it2=ma.find(4);//参数为需要查找元素的键值
if(it2==ma.end())
{
cout<<"查找失败"<<endl;
}
else
{
cout<<it2->first<<" "<<it2->second<<endl;
}
//equal_range的使用和异常处理std::pair<iterator, iterator> equal_range(const key_type& __x)
//该函数返回两个迭代器,封装在pair中
std::pair<map<int,string>::iterator,map<int,string>::iterator>pair3=ma.equal_range(4);
if(pair3.first==ma.end())
{
cout<<"键值为4的值不存在"<<endl;
}
else
{
cout<<pair3.first->first<<"\t"<<pair3.first->second<<endl;
}
if(pair3.second==ma.end())
{
cout<<"键值为5的值不存在"<<endl;
}
else
{
cout<<pair3.second->first<<"\t"<<pair3.second->second<<endl;
}
//容器元素的删除
while(!ma.empty())
{
map<int,string>::iterator it1=ma.begin();
cout<<it1->first<<"\t"<<it1->second<<endl;
ma.erase(it1);
}
}
int main()
{
main1();
return 0;
}
multimap容器的操作。multimap容器中一个key值可以对应多个键值的值
#include<iostream>
#include<map>
#include<string>
void main01()
{
using std::endl;
using std::cout;
using std::multimap;
multimap<string,Person>mul;
}
int main()
{
main01();
}
如果一个类中重载了函数调用操作符(),则这个类所定义的对象叫做函数对象,或者函数名(回调函数的入口地址)或则函数指针都叫做函数对象,亦称函数符。
- 一元函数对象:在类中重载的函数调用操作符函数中只有一个参数,用这个类定义的对象叫做一元函数对象
- 一元函数谓词:一个函数只有一个参数,且函数返回值类型为bool类型。一元函数对象和一元函数谓词与此类似
#include<iostream>
#include<list>
#include<algorithm>
template<class T>
class Functor
{
public:
void operator()(T&t)
{
std::cout<<t<<"\t"<<std::endl;
}
private:
};
int main()
{
using std::list;
int a=200;
Functor<int>fun;
fun(a);//fun为函数对象或则仿函数对象
list<int>li;
li.push_back(100);
li.push_back(200);
li.push_back(300);
//利用for_each算法遍历容器
//_Funct for_each(_IIter, _IIter, _Funct);
//for_each函数返回值为函数对象,第三个参数也为函数对象
for_each(li.begin(),li.end(),Functor<int>());//Functor<int>()为匿名仿函数对象
for_each(li.begin(),li.end(),fun);
return 0;
}
预定义函数对象:标准模板库stl提供了很多预定义的函数对象种类很多,包括算术函数对象,逻辑函数对象,关系函数对象。大多函数对象在头文件functional中定义
#include<iostream>
#include<list>
#include<functional>
#include<string>
#include<algorithm>
int main()
{
using std::plus;
using std::string;
using std::list;
using std::equal_to;
plus<int>pl;//plus为在functional中预定义好的算术函数对象中的一种
int a=100,b=200;
int c=pl(a,b);
std::cout<<"c:"<<c<<std::endl;
plus<string>p;
string f="Hello",d="World";
string e=p(f,d);
std::cout<<"e:"<<e<<std::endl;
//利用算法统计一个字符串在容器中的次数
list<string>li;
li.push_back("Hello");
li.push_back("World");
li.push_back("Hey");
li.push_back("Hello");
string sc="Hello";
//bind2nd为函数适配器
int count=count_if(li.begin(),li.end(),bind2nd(equal_to<string>(),sc));
std::cout<<"count:"<<count<<std::endl;
return 0;
}
常用的遍历算法:for_each函数可以修改容器元素.transform函数也可以修改容器元素
#include<iostream>
#include<vector>
#include<algorithm>
using std::vector;
class funct
{
public:
void operator()(int&n)
{
num++;
std::cout<<n<<"\t";
}
void MyPrint()
{
std::cout<<"num:"<<num<<std::endl;
}
funct()
{
num=0;
}
private:
int num;
};
int ShowElem1(int n)
{
return n;
}
void MyPrint( vector<int>&ve)
{
for(vector<int>::iterator it=ve.begin();it!=ve.end();it++)
{
std::cout<<*it<<"\t";
}
std::cout<<std::endl;
}
void ShowElem(int&n)
{
std::cout<<n<<"\t";
}
void main01()
{
using std::cout;
using std::endl;
vector<int>ve,ve1;
ve.push_back(1);
ve.push_back(3);
ve.push_back(5);
//利用迭代器的方式遍历容器
MyPrint(ve);
//利用for_each算法来遍历容器
//ShowElem为回调函数的入口地址
for_each(ve.begin(),ve.end(),ShowElem);
cout<<endl;
//funct()将会生成一个匿名的函数对象
for_each(ve.begin(),ve.end(),funct());
cout<<endl;
//函数对象当返回值可以记录函数被调用的次数
funct fu=for_each(ve.begin(),ve.end(),funct());
fu.MyPrint();
cout<<endl;
//less<int>利用transform算法来遍历容器
}
int main()
{
main01();
return 0;
}
排序算法之sort函数
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using std::vector;
using std::cout;
using std::endl;
using std::less;
using std::greater;
class Student
{
private:
double grades;//学生成绩
unsigned int num;//学生学号
public:
Student(double grades,unsigned int num)
{
this->grades=grades;
this->num=num;
}
void MyPrint()
{
cout<<"grades:"<<grades<<" "<<" num:"<<num<<endl;
}
int GetGrades()
{
return grades;
}
int GetNum()
{
return num;
}
};
bool MyCompare (Student &s1,Student &s2)
{
if(s1.GetGrades()>s2.GetGrades())
return true;
else
return false;
}
using std::sort;
void PrintV( vector<int>&ve)
{
for(vector<int>::iterator it=ve.begin();it!=ve.end();it++)
{
cout<<*it<<"\t";
}
cout<<endl;
}
void main01()
{
vector<int>ve;
ve.push_back(23);
ve.push_back(13);
ve.push_back(33);
ve.push_back(3);
//1.对普通数据类型进行排序
sort(ve.begin(),ve.end());//sort算法将容器中的元素从小到大排列
//上一句相当于sort(ve.begin(),ve.end(),less<int>());
PrintV(ve);
sort(ve.begin(),ve.end(),greater<int>());//将容器中的元素从大到小排列
PrintV(ve);
//2.对自定义数据进行排序
Student s1(98.2,3);
Student s2(34.7,1);
Student s3(66.6,2);
Student s4(100,4);
vector<Student>v;
v.push_back(s4);
v.push_back(s2);
v.push_back(s3);
v.push_back(s1);
//MyCompare为回调函数的地址,二元谓词
sort(v.begin(),v.end(),MyCompare);
for(vector<Student>::iterator it1=v.begin();it1!=v.end();it1++)
{
it1->MyPrint();
}
}
int main()
{
main01();
return 0;
}
常用的集合算法:
- set_union:构造一个有序序列,包含两个有序序列的并集
- set_intersaction:构造一个有序序列,包含两个有序序列的交集
- set_diffferance:构造一个有序序列,包含一个有序序列的元素而不包含另一个有序序列的元素
//1.利用stl算法对常规数组进行排序
//2.将数据拷贝到stl容器中
//3.将容器中的数据直接拷贝到输出流中
//4.利用reverse iterator迭代器反向遍历容器中的元素
#include<iostream>
#include<algorithm>
#include<vector>
#include<iterator>
void MyPrint(double&ve)
{
std::cout<<ve<<" ";
}
void main01()
{
using namespace std;
const int lengh=10;
double arr[lengh]={13.4,34.5,24,78.9};
sort(arr,arr+lengh);
for(int i=0;i<lengh;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
vector<double>ve(10);//为动态数组分配十个字节大小的空间
//inline _OI copy(_II __first, _II __last, _OI __result)
//copy将覆盖容器中已有的数据元素
copy(arr,arr+lengh,ve.begin());
for(vector<double>::iterator it=ve.begin();it!=ve.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//反反向遍历容器中的元素
for(vector<double>::reverse_iterator it2=ve.rbegin();it2!=ve.rend();it2++)
{
cout<<*it2<<" ";
}
cout<<endl;
//_Funct for_each(_IIter, _IIter, _Funct);
//利用算法for_each对容器进行遍历
for_each(ve.begin(),ve.end(),MyPrint);
cout<<endl;
ostream_iterator<double,char>it1(cout," ");
copy(ve.begin(),ve.end(),it1);
cout<<endl;
//利用算法sort对vector容器进行排序
sort(ve.begin(),ve.end(),greater<int>());
for(vector<double>::iterator it3=ve.begin();it3!=ve.end();it3++)
{
cout<<*it3<<" ";
}
cout<<endl;
}
int main()
{
main01();
return 0;
}
functor函数对象(函数符)的巩固
#include<iostream>
#include<map>
#include<algorithm>
#include<string>
class Student
{
public:
std::string name;
double scores;
public:
Student(const std::string n=" ",double s=0):name(n),scores(s){}
bool operator()(const Student&stu1,const Student&stu2)
{
return stu1.scores>stu2.scores;
}
};
void main01()
{
using namespace std;
Student stu1("wang ming",98),stu2("xiao hua",68),stu3;
multimap<int,Student>mul;
mul.insert(std::pair<int,Student>(1,stu1));
mul.insert(std::pair<int,Student>(2,stu2));
for(multimap<int,Student>::iterator it=mul.begin();it!=mul.end();it++)
{
cout<<it->first<<" "<<(it->second).name<<" "<<(it->second).scores<<endl;
}
}
int main()
{
main01();
return 0;
}
容器类中的方法与stl算法的区别:stl算法具有通用性,类中的方法具有针对性以list容器中的方法remove和stl算法remove为例尽量使用容器类自身的方法
#include<iostream>
#include<list>
#include<algorithm>
using std::list;
using std::cout;
using std::endl;
void PrintMassage(const list<int>&li)
{
for(list<int>::const_iterator it=li.begin();it!=li.end();it++)
{
cout<<*it<<" ";
}
}
void main01()
{
const int num=5;
int arr[num]={23,45,67,45,35};
list<int>li(arr,arr+num);
list<int>l(li);
PrintMassage(li);
cout<<endl;
//调用list容器类的方法
li.remove(45);
cout<<"after remove:";
PrintMassage(li);
cout<<endl;
PrintMassage(l); //23 45 67 45 35
cout<<endl;
//调用stl算法
list<int>::iterator it1=remove(l.begin(),l.end(),45);
cout<<"after remove:";
PrintMassage(l); //23 67 35 45 35
cout<<endl;
l.erase(it1,l.end());
PrintMassage(l); //23,67,35
}
int main()
{
main01();
return 0;
}
//上述案例表明:stl算法remove不能自动调整容器的长度,而方法可以
memset函数:对新分配的内存空间初始化
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char arr[10];
//memset函数的原型声明
//void* __cdecl __MINGW_NOTHROW memset (void*, int, size_t);
//memset函数对void*指向的内存空间size_t大小的内存块初始化为int
memset(arr,'A',sizeof(arr) - 1);
arr[9]='\0';
cout<<arr<<endl;
cout<<sizeof(arr)<<endl;
return 0;
}
initial_list类模板的使用
#include<iostream>
#include<vector>
#include<initializer_list>
void main01()
{
using namespace std;
vector<int>ve{1, 2, 3};
for(vector<int>::iterator p=ve.begin();p!=ve.end();p++)
{
cout<<*p<<" ";
}
}
int main()
{
main01();
return 0;
}
三个智能指针模板类的使用:auto_ptr,unique_ptr,share_ptr.
#include<iostream>
#include<memory>//for auto_ptr class
#include<string>
using namespace std;
int main()
{
//模板类auto_ptr的成员函数会为智能指针分配内存,并且无需
//人工使用delete来释放分配的内存。
auto_ptr<double>p1(new(double));
*p1=100;
cout<<*p1<<endl;
auto_ptr<string>p2(new string("HelloWorld"));
cout<<*p2<<endl;
//auto_ptr和unique_ptr建立所有权的概念:将一个auto_ptr类智能指针
//赋值给另外一个同类型的智能指针时,所有权将会转让,因此不能对之
//前的智能指针执行解除引用操作。
auto_ptr<string>p3=p2;
cout<<*p3<<endl;
//cout<<*p2<<endl;error,所有权以被转让,程序运行时中断
//将一个unique_ptr类智能指针赋值给另外一个同类型的智能指针时(源智
//能指针存在一段时间),编译阶段将会报错。源智能指针不是临时的可以
//通过
// 相比程序运行时中断,编译期报错更适合
return 0;
}
运算符alignof(cpp11新增)以类型为参数,指出对齐方式,决定数据在内存中的存储大小
#include<iostream>
int main()
{
int a=100;
std::cout<<alignof(int)<<std::endl; // 4
return 0;
}
c++允许定义一个指向类成员的成员指针,并通过解除引用来访问类成员。也允许定义一个指向类中方法的函数指针,通过函数指针来调用方法。(未知)
#include<iostream>
class Data
{
public:
int a;
public:
Data(){a=0;}
Data(int b):a(b){}
~Data(){};
};
int main()
{
Data da;
int Data:: *ptr=&Data::a;//定义一个成员指针
std::cout<<da.*ptr<<std::endl;
return 0;
}