三天学会C++ 之一
●对象与类的概念
对象是现实世界中的一个实体,其特征是:
1、每一个对象必须有一个名字以区别于其它对象;
2、用属性(或叫状态)来描述它的某些特征;
3、有一组操作,每一个操作决定对象的一种行为。
类的精确定义:具有共性的实体的抽象,类是创建对象的样板,包含对创建对象的状态描述和对操作行为的说明。
●数据的抽象
是通过对数据实例的分析,抽取其共同的结果。
●数据的封装:
把对象的属性和操作结合成一个整体,并尽可能的隐藏对象的内部细节。
●抽象与封装的关系:
1、抽象和封装是互补的;
2、好的抽象有利于封装;
3、封装的实体则帮助维护抽象的完整性;
4、抽象先于封装。
●C与c++ 在定义变量上的区别;
C++中允许在代码块中的任何地方说明局部变量:
变量从其说明地点到该变量所在的最小分程序末的范围内有效(即在其作用域有效)。
作用域运算符:“::”
如果希望在局部变量的作用域内使用同名的全局变量,可以在该变量前加上“::” ,“::”称为作用域运算符。否则在该作用域内该同名的全局变量会暂时被局部变量屏蔽掉。
在C++中,结构名、联合名(共用体名)、枚举名都是类型名。如:
enum bool{FALSE,TRUE};
struct string
{
char *prt;
int length;
};
-
在C中:
enum bool done;
struct string str;
-
在C++中:
bool done;
string str;
●const
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
●内联函数
在函数说明前冠以关键字“inline”,则该函数就被声明为内联函数。
每当程序中出现对该函数的调用时,C++编译器使用函数体内的代码替代函数调用表达式
优点:快代码的执行,减少系统开销
内联函数与宏定义相比
使用内联函数替代宏定义,可以消除宏定义的不安全性。内联函数具有宏定义的所有优点而没有缺点。
例:
#include <iostream.h>
//#define Max(x,y) x>y?x:y // 定义为行2
inline int Max(int x, int y);
int main()
{
int a,b;
a = Max(5,9);
b = 2*Max(5,9); //这里若以行2的宏定义替换,得到的结果是5,宏展开如下:2*5>9?5:9,所以结果是5.而内联会先运算得到Max的值5,后运算得18
cout << a << ',' << b <<endl;
return 0;
}
int Max(int x, int y)
{
return x>y?x:y;
}
●带有缺省参数的函数
C++在声明函数原型时,可为一个或多个参数指定缺省参数值,以后调用此函数,若省略其中某一参数,C++自动地以缺省值作为相应参数的值。例如函数原型说明为:
int special(int x=5,float y=5.3);
当进行函数调用时,可以有以下几种形式:
1) special(100,79.8); // x=100,y=79.8
2) special(25); // x=25,y=5.3
3) special(); // x=5,y=5.3
注意:
1、只能在声明时设置默认参数
2、缺省参数都必须是从右到左定义
如:int fun(int i,int j=5,int k);//错误,k未使用
3、调用时实参对形参的初始化必须是从左向右的
例:
#include <iostream.h>
void display(char *a="Hello");
void main()
{
display("Hello world!");
display();
}
void display(char *a)
{
cout<<a<<endl;
}
●函数重载
当两个或者两个以上的函数共用一个函数名时,称为函数的重载。
在传统的C语言中,函数名必须是唯一的,也就是说不允许出现同名的函数。当要求编写求整数、浮点数和双精度的平方数的函数时,若用C来实现必须编写三个函数:
iSquare(int x)
fSquare(float x)
dSquare(double x)
C++ 中,允许功能相同的函数同名:
Square(int x)
Square(float x)
Square(double x)
在C++中用户可以重载函数,即只要函数参数的类型不同,或者参数的个数不同,或者二者兼而有之,两个或两个以上的函数可以使用相同的函数名。
例:
//函数重载
#include <iostream.h>
int square(int x)
{
return x*x;
}
float square(float x)
{
return x*x;
}
double square(double x)
{
return x*x;
}
int main()
{
int i=12;
float f=3.4f;
double d=5.67;
cout<<i<<'*'<<i<<'='<<square(i)<<endl;
cout<<f<<'*'<<f<<'='<<square(f)<<endl;
cout<<d<<'*'<<d<<'='<<square(d)<<endl;
return 0;
}
说明:
1、重载函数应是根据参数个数或参数类型来确定调用哪一个重载版本
错误例如:
int mul(int x,int y);
double mul(int x,int y);
2、一般而言,重载函数应执行相同的功能,例如abs()函数一般用来返回一个数的绝对值,如果重载abs()函数,让它返回一个数的平方根,则是不可取的。
函数重载与默认参数注意事项:
-
默认参数可将一系列简单的重载函数合成一个。如有三个重载函数:
void func(int x,int y)
{
cout<<x<<’,’<<y<<endl;
}
void func(int x)
{
func(x,10);
}
void func()
{
func(5,10);
}
可以用下面的默认参数函数来代替:
void func(int x=5,int y=10)
{
cout<<x<<’,’<<y<<endl;
}
-
如果一组重载函数(可能带有默认参数)都允许相同实参个数的调用,将会引起调用的二义性。如有:
void func(int x); //1
void func(int x,int y=4); //2
void func(int x=3,int y=4); //3
调用时: func(7); //错误,调用哪一个?
func(20,30); //错误,调用后两个中的哪一个?
●强制类型转换
-
C中使用形如 (int)x的形式。
-
C++中还允许另一种更为方便的函数调用方法形式,如int(x)。
-
以上两种方法C++都能接受,但推荐使用后一种方法。
●new和delete运算符
在C中动态内存分配是靠malloc()和free()两个函数完成的。
(1)分配内存:p=new 数据类型;
(2)释放内存:delete p;
说明:
1、new在为简单变量分配内存的同时进行初始化。如:int *p;p=new int(90);
2、使用new可以为数组动态分配内存。如: int *p=new int[10];
3、释放动态分配的数组内存区时,使用如下的格式: delete p; delete []p; 4、使用new动态分配内存时,如果没有足够的内存时,将返回空指针(NULL)。
●引用
引用就是给变量一个别名,使指针运算更加方便。
引用是个别名,当建立引用时,程序用另一个变量或对象(目标)的名字初始化他。从那时起,引用作为目标而使用,对引用的改动实际就是对目标的改动。
-
引用的定义
先写上目标的类型,后跟引用运算符“&”,然后是引用的名字。
类型名 &别名=变量名或对象名;
如: int a=5;
int &b=a;
注意:
1)、 定义引用时必须初始化,之后不可重新赋新值
如下是错误的:
int a;
int &b; //错误
b=a;
初始化可以为另一个引用名,如下:
int a;
int &b=a;
int &c=b;
2)、不能建立引用的数组,因为数组是某个数据类型的集合,数组名表示该元素集合空间的起始地址,它自己不是一个名副其实的数据类型。如:
int a[10];
int &ra[10] = a; //错误
3)、对void进行引用是不允许的,void 只是在语法上相当于一个类型,本质上不是一种类型。
4)、没有引用的引用,也没有引用的指针。因为引用本身不是类型,定义引用在概念上不产生内存空间,所以引用之上的引用不存在。
5)、引用不能用类型去初始化,因为引用是变量或对象的引用,而不是类型的引用。例:
int &ra = int; //错误
6)、有空指针,无空引用。
-
引用作参数
-
引用作参数是引用的重要用途。如:
int func(int &x,int &y)
-
两个数互换的函数
例2.18:使用指针交换
void swap(int *m,int *n)
{
int temp;
temp=*m; *m=*n; *n=temp;
}
void main()
{
int a=10,b=20;
swap(&a,&b);
cout<<a<<b<<endl;
}
例2.20:使用引用
void swap(int &m,int &n)
{
int temp;
temp=m; m=n; n=temp;
}
void main()
{
int a=10,b=20;
swap(a,b);
cout<<a<<b<<endl;
}
-
通过引用参数产生的效果同按地址传递是一样的,但其语法更清楚简单,因为在调用函数的所有参数前不需要间接引用运算符*,原函数中传送的参数也不必是引用变量。
-
C++主张用引用传递取代地址传递的方式,因为引用语法容易且不易出错。
-
函数返回值为引用
-
为了将该函数用在赋值运算符的左边,可将函数的返回值说明为引用。
例2.21
#include <iostream.h>
int a[]={1,3,5,7,9};
int &index(int i); //声明返回引用的函数
void main()
{
index(2)=25;
cout<<index(2);
}
int &index(int i)
{
return a[i];
}