如果a=1,b=2;则屏幕上显示a+b=3。
“>>”是提取符,用到cin上用来把键盘上输入的数赋值给变量。
使用形式为:
cin>>表达式>>表达式...。
这里的提取符也可以有多个,每个后边跟一个表达式,这里的表达式一般是用来存放输入值的变量。
比如,inta,b;cin>>a>>b;后面这个语句要求从键盘上输入两个整型数,两个数之间用空格分隔,如果输入34,则变量a的值为3,b的值为4
3.头文件
1.所有的MFC实现文件第一条语句都是:
#include"stdafx.h"。
在它前面的所有代码将被忽略,所以其他的头文件应该在这一行后面被包含。
否则,你将会得到“Nosuchfileordirectory”这样让你百思不得其解的错误提示
4.宏
1.防止一个头文件被重复包含
#ifndefBODYDEF_H
#defineBODYDEF_H
//头文件内容
#endif
2.
5.自定义类型
1.枚举型
enum 枚举类型名 { 变量值列表}; 变量值列表里都是整型变量,另外不要忘记最后面的分号!
比如,enumweekday{sun,mon,tue,wed,thu,fri,sat};
这里的枚举元素sun、mon...都没有指定值,它们就使用默认值,依次为0,1,2...。
即sun就是0,mon就是1,...sat是6。
也可以在声明枚举类型时指定枚举元素的值,比如
enumweekday{sun=7,mon=1,tue,wed,thu,fri,sat};
这里sun就是7,mon是1,后面的值在mon的基础上依次加1,即tue等于2,wed为3...sat是6。
枚举元素按常量处理,不能对它们赋值除了声明的时候,像sun=0;这样的语句就是非法的
2.结构体
struct结构体名
{
数据类型成员名1;
数据类型成员名2;
:
数据类型成员名n;
};
3.类型定义语句
使用的语法形式是:
typedef 已有类型名 新类型名表;。
新类型名表中可以有多个标识符,它们之间用逗号分开,就是在一个typedef语句中可以为一个已有数据类型声明多个别名,比如
typedef double length,width;
length a;
width b;
4.引用调用
引用的形式是:
类型标识符&引用名。
比如:
int i,j;
int&ri=i; //建立一个int型的引用ri,并将其初始化为变量i的一个别名
j=10;
ri=j; //相当于i=j;
声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象;一旦一个引用被初始化后,就不能改为指向其它对象。
值调用和引用调用的区别只是函数的形参写法不同
5.带默认形参值的函数
默认参数值必须按照从右向左的顺序定义
intadd(intx,inty=5,intz=6);//正确
intadd(intx=1,inty=5,intz);//错误
intadd(intx=1,inty,intz=6);//错误
调用出现在函数体实现之前时,默认形参值必须在函数原型中也就是声明时给出;而当调用出现在函数体实现之后时,默认形参值需在函数实现时给出。
例如:
调用在实现前时:
intadd(intx=5,inty=6);
intmain()
{
add();//调用在实现前
return0;
}
intadd(intx,inty)
{
returnx+y;
}
调用在实现后时:
intadd(intx=5,inty=6)
{
returnx+y;
}
intmain()
{
add();//调用在实现后
return0;
}
6.内联函数
inline类型标识符被调函数名(含类型说明的形参表)
内联函数体内不能有循环语句和switch语句;
内联函数的定义必须出现在内联函数第一次被调用之前;
对内联函数不能进行异常接口声明,就是不能声明可能抛出的异常
7.函数模板
template//此句中的typename和class是等效的
函数定义
#include
usingnamespacestd;
template
Tabs(Tx)
{
returnx<0?
-x:
x;
}
int_tmain(intargc,_TCHAR*argv[])
{
intn=5;
doubled=-2.3;
cout<cout<return0;
}
6.面向对象
1.构造函数
函数名和类名是一样的,而且没有返回值
作用:
对象的初始化
2.拷贝构造函数
class类名
{
public:
类名(形参);//构造函数
类名(类名&对象名);//拷贝构造函数
...
};
类名:
:
类(类名&对象名)//拷贝构造函数的实现
{
函数体
}
classPoint
{
public:
Point(intxx=0,intyy=0){X=xx;Y=yy;}
Point(Point&p);
intGetX(){returnX;}
intGetY(){returnY;}
private:
intX,Y;
};
此类中声明了内联构造函数和拷贝构造函数。
拷贝构造函数的实现如下:
Point:
:
Point(Point&p)
{
X=p.X;
Y=p.Y;
cout<<"拷贝构造函数被调用"<}
拷贝构造函数在以下三种情况下会被调用:
a.当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值。
intmain()
{
PointA(1,2);
PointB(A);//拷贝构造函数被调用
cout<return0;
}
b.若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。
例如:
voidfun1(Pointp)
{
cout<
}
intmain()
{
PointA(1,2);
fun1(A);//调用拷贝构造函数
return0;
}
c.当函数的返回值是类对象时,系统自动调用拷贝构造函数。
例如:
Pointfun2()
{
PointA(1,2);
returnA;//调用拷贝构造函数
}
intmain()
{
PointB;
B=fun2();
return0;
}
最后这种情况怎么调用的拷贝构造函数呢?
对象A是局部对象,在fun2函数执行完就释放了,那怎么将它拷贝给对象B呢?
编译器在执行B=fun2()时会创建一个临时的无名对象,在执行returnA时实际上是调用了拷贝构造函数将A的值拷贝到了临时对象中,A就释放了,然后将临时对象的值再拷贝到对象B中。
3.析构函数
析构函数是类的一个公有函数成员,它的名称是在类名前加“~”形成,不能有返回值
析构函数的执行顺序与构造函数正好相反。
4.前向引用申明
classB;//前向引用声明
classA
{
public:
voidf(Bb);
};
classB
{
public:
voidg(Aa);
};
7.类模板(难点)
1.申明
template<模板参数表>
类声明
2.申明形式
用类模板建立对象时的声明形式为:
模板<模板参数表>对象名1,...,对象名n;
8.作用域
1.符号“.”用于访问对象的成员,包括函数成员。
比如,a.fun(x)用来调用对象a的函数fun。
如果ptr是指向类A的一个对象的指针,则访问其数据成员x的方式为ptr->x,访问函数成员的形式如:
ptr->fun(x)。
9.生存期
1.静态生存期
staticintx;这个语句就是将x声明为具有静态生存期的变量,也成为静态变量
2.静态局部变量如果没有进行显式初始化,那么它将被默认初始化为0
3.静态成员函数
静态成员的好处就是内存中只有一份拷贝,可以直接通过类名访问
静态成员函数跟静态数据成员一样,也是由类的所有对象所共有,由他们共同维护和使用。
声明时前面也要加static关键字,比如,staticvoidfun(void);。
我们可以通过类名或对象名调用公有类型的静态成员函数,而非静态成员函数只能由对象名调用。
静态成员函数可以访问该类的静态数据成员和其他静态成员函数,如果要访问非静态数据成员,则必须将对象作为参数传递进去,然后通过传进去的对象名来访问。
classA
{
public:
staticvoidf(Aa);
private:
intx;
};
voidA:
:
f(Aa)
{
cout<cout<}
10.各种类别
1.友元
类B是类A的友元类,B的成员函数可以访问类A的对象的私有成员和保护成员。
友元关系不能传递。
classA
{
public:
voidDisplay(){cout<friendclassB;
private:
intx;
}
classB
{
public:
voidSet(inti);
voidDisplay();
private:
Aa;
};
voidB:
:
Set(inti)
{
a.x=i;//因为类B是类A的友元类,所以类B的成员函数可以访问类A对象的私有成员
}
voidB:
:
Display()
{
a.Display();
}
2.常对象
常对象不能调用普通的成员函数
定义常对象时必须对其进行初始化,并且不能改变其数据成员的值
3.常引用
常引用的声明形式为:
const类型说明符&引用名
4.常的成员函数
常成员函数的声明形式为:
类型说明符函数名(参数表)const;。
a.常成员函数在声明和实现时都要带const关键字;
b.常成员函数不能修改对象的数据成员,也不能访问类中没有用const声明的非常成员函数;
c.常对象只能调用它的常成员函数,不能调用其他的普通成员函数;
d.const关键字可以被用于参与对重载函数的区分,比如,如果有两个这样声明的函数:
voidfun();voidfun()const;,则它们是重载函数
5.类的常数据成员
6.多文件结构和编译预处理命令
7.#undef用来删除由#define定义的宏,使其不再起作用
8.数组
如果我们对数组初始化时给出了全部元素的初值,则第一位的元素个数可以不用显式说明,例如:
inta[2][2]={1,2,1,2};等价于inta[][2]={1,2,1,2};
当数组的元素是某个类的对象时此数组就是对象数组。
声明一维对象数组的形式为:
类名数组名[下标表达式];
函数的参数可以是数组元素也可以是数组名
9.指针
内存的基本存储单位是字节,一个字节由8个二进制位组成
声明的形式是:
数据类型*标识符;
例如,int*p;声明了一个指针变量p,它指向int类型的数据,用来存放int型数据的地址
“&”出现在声明语句中被声明的变量名之前时,表示声明的是引用,例如,int&rf;
1.在声明指针时对其进行初始化,也就是赋一个初值,初始化形式为:
数据类型*指针名=初始地址值;。
2.在声明指针后,单独给它赋值,赋值的语法形式为:
指针名=地址;。
如果我们像方式1中使用变量地址为指针初始化,或者像方式2中将变量地址赋给指针,此变量必须在此之前声明过,并且这个变量的类型要和指针类型一样。
可以将一个已经赋值的指针赋值给另一个指针,让多个指针指向相同的变量。
inta[5];//声明一个整型数组
int*p1=a;//声明指针p1,并用数组首地址a来初始化p1
int*p2;//声明指针p2
p2=a;//将数组首地址a赋值给指针p2,数组名就是数组的首地址
cout<<"Outputintpointeri="<<*p<3.常量指针
constchar*name="Tom";//指向常量的指针
chars[]="Lili";
name=s; //正确,name本身的值可以改变
*name=’a’; //编译时指出错误,不能通过name修改指向的对象
我们还可以声明指针常量,这时候指针本身的值不能改变,例如:
inta=1;
intb=2;
int*constp=&a; //声明指针常量p
p=&b; //错误,不能改变指针常量p的值
4.Void类型指针
p1=(int*)p;//用强制类型转换的方式将void指针p的指针赋给int型指针p1
5.数组与指针
a和&a[0]是完全等价的
数组名a代表了数组a的首地址,它是一个指针常量,也就是不能改变,所以,注意,不能进行自增自减运算
a是数组第一个元素的地址,那么第i+1个元素也就是下标为i的元素的地址就是a+i,第i+1个元素就是*(a+i)。
例如,*a就是a[0],*(a+7)就是a[7]
intarray[2][3]={{1,2,3},{2,4,6}};
for(inti=0;i<2;i++)
{
for(intj=0;j<3;j++)
{
cout<<*(*(array+i)+j)<<"";
//也可以是cout< }
cout< }
普通函数只能返回一个变量或对象,但指针型的函数可以在函数调用结束时将大量数据从被调函数返回到主调函数中,这就是它的好处
6.指针函数
数据类型*函数名(参数表)
{
函数体
}
声明的语法形式是:
数据类型(*函数指针名)(形参列表);
声明的语法形式是:
数据类型(*函数指针名)(形参列表);
voidshow(intx)
{
cout< }
void(*show_pointer)(int); //声明一个void类型的函数指针
intmain()
{
inta=10;
show_pointer=show; //函数指针show_pointer指向show
show_pointer(a); //函数指针调用
return0;
}
7.对象指针
类名*对象指针名;
对象指针名->公有成员名;
指向类的非静态成员的指针
声明:
类型说明符类名:
:
*指针名;//声明指向公有数据成员的指针
类型说明符(类名:
:
*指针名)(形参表);//声明指向公有成员函数的指针
赋值:
指针名=&类名:
:
数据成员名;
通过对象和指向数据成员的指针访问公有数据成员的语法形式为:
对象名.*指向数据成员的指针名
或者对象指针名->*指向数据成员的指针名
为指向成员函数的指针赋值的语法形式为:
指针名=&类名:
:
函数成员名;
在上面的形式为成员函数指针赋值以后还不能直接用此指针调用成员函数,必须先声明了类的对象,再通过对象和指向非静态成员函数的指针调用成员函数。
调用的语法形式为:
(对象名.*指向成员函数的指针名)(形参表)
或者(对象指针名->*指向成员函数的指针名)(形参表)
10.New和delete
用new动态分配的内存只能用delete释放一次,如果释放第二次会出现错误
用new动态创建多维数组的语法形式为:
new类型名T[下标表达式1][下标表达式2]...;
上面的下标表达式1可以是任何结果为正整数的表达式,而其他下标表达式必须是结果为正整数的常量表达式
11.字符串
一次性输入:
charstr[5];cin>>str;
一次性输出:
charstr[5]="love";cout<charstr[5]={108,111,118,101,0};//以逗号分隔的ASCII码为字符数组初始化赋值
charstr[5]={'l','o','v','e','\0'};//以逗号分隔的字符常量为字符数组初始化赋值
charstr[5]="love";//以字符串常量为字符数组初始化赋值
12.继承派生
如果没有显式指定继承方式,则默认为私有继承
派生类不能从基类继承构造函数和析构函数,但是派生类同样需要有初始化和清理,所以我们需要为派生类添加新的构造函数和析构函数
派生类不能访问基类的私有成员
13.作用域分辨符
我们可以通过基类名和作用域分辨符来访问基类中的同名成员。
作用域分辨符就是“:
:
”,在派生类内部访问基类同名成员的语法形式是:
基类名:
:
数据成员名;//数据成员
基类名:
:
函数成员名(参数表);//函数成员
如果是在派生类外通过派生类对象访问的话,前面还要加上“派生类对象名.”:
派生类对象名.基类名:
:
数据成员名;//数据成员
派生类对象名.基类名:
:
函数成员名(参数表);//函数成员
14.赋值兼容
赋值兼容规则就是指在基类对象可以使用的地方都可以用公有派生类对象来代替
15.运算符
规则
1.一般重定义的功能与原运算符的功能相似,运算符重载的参数个数与原运算符的操作数个数相同,而且至少有一个参数属于自定义数据类型。
2.运算符重载后其优先级和结合性都与原运算符相同
3.除了类属关系运算符“.”、成员指针运算符“.*”、作用域分辨符“:
:
”、sizeof运算符和条件运算符“?
:
”这五种运算符外,其余C++运算符都能重载,而且只有C++中已有的运算符可以重载。
申明
运算符重载为类的成员函数时的声明形式为:
函数类型operator运算符(参数表)
{
函数体;
}
运算符重载为类的友元函数时的声明形式为:
friend函数类型operator运算符(参数表)
{
函数体;
}
运算符重载友元函数访问类的对象的数据时,必须通过类的对象名访问
16.虚函数
1.虚函数是非静态的成员函数,一定不能是静态(static)的成员函数
2.注意
一般的虚函数声明形式为:
virtual函数类型函数名(形参表)
{
函数体
}
如果成员函数的实现在类的声明外给出时,则虚函数的声明只能出现在类的成员函数声明中,而不能在成员函数实现时出现.
17.抽象类
抽象类:
含有纯虚函数的类
1.不能定义抽象类的对象,只能从它继承出非抽象派生类再实例化