C++学习笔记
第三章 函数
3.2 内联函数
普通的函数调用会降低程序的执行效率,增加时间和空间方面的开销。因此对于一些功能较简单、规模较小又使用频繁的函数,可以设计为内联函数。内联函数不是在调用时发生控制转移,而是在编译的时候将函数体嵌入在每一个调用处。可以节省参数传递、控制转移等开销。
存在对自身直接递归调用的函数是无法以内联方式处理的。
形式:
inline 类型说明符 函数名(含类型说明的形参表){
语句序列
}
1 #include<iostream> 2 using namespace std; 3 const double PI=3.14159265358979; 4 5 inline double calArea(double radius){ //内联函数根据圆的半径计算其面积 6 return PI*radius*radius; 7 } 8 9 int main(){ 10 double r=3.0; 11 //调用内联函数求圆的面积,编译时此处被替换为calArea函数体语句 12 double area=calArea(r); 13 cout<<area<<endl; 14 return 0; 15 }
28.2743
3.3 带默认形参值的函数
(1)在有默认值的形参后面,不能出现无默认值的形参。
例如:int add(int x,int y=5,int z=6 ) ; //正确
int add(int x=1,int y=5,int z) ; //错误
(2)在相同的作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,即使前后定义的值相同也不行。
1 #include<iostream> 2 #include<iomanip> 3 using namespace std; 4 int getVolume(int length,int width=2,int height=3); 5 6 int main() 7 { 8 const int x=10,y=12,z=15; 9 cout<<"Some box data is:"; 10 cout<<getVolume(x,y,z)<<endl; 11 cout<<"Some box data is:"; 12 cout<<getVolume(x,y)<<endl; 13 cout<<"Some box data is:"; 14 cout<<getVolume(x)<<endl; 15 return 0; 16 } 17 18 int getVolume(int length,int width/*=2*/,int height/*=3*/){ 19 cout<<setw(5)<<length<<setw(5)<<width<<setw(5)<<height<<'\t'; 20 return length*width*height; 21 }
Some box data is: 10 12 15 1800 Some box data is: 10 12 3 360 Some box data is: 10 2 3 60
3.4 函数重载
c++语言中提供了对函数重载的支持,使我们在编程时可以对不同的功能赋予相同的函数名,编译时会根据上下文(实参的类型和个数)来确定使用哪一具体功能。
两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型以及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。
*不要将不同功能的函数定义为重载函数,以免出现对调用结果的误解混淆。
正确:
int add(int x,int y) ;float add(float x,float y) ; //形参类型不同
int add(int x,int y); int add(int x,int y,int z) ; //形参个数不同
错误:
int add(int x,int y); int add(int a,int b); //编译器不以形参名来区分函数
int add(int x,int y); void add(int x,int y); //编译器不以返回值来区分函数
当使用具有默认形参值的函数重载形式时,需要注意防止二义性。例如下面的两个函数原型,在编译时便无法区别为不同形式的重载形式:
void fun(int length,int width=2,int height=33);
void fun(int length);
当调用fun(1);时便无法确定应该执行那个重载函数。
1 #include<iostream> 2 using namespace std; 3 int sumOfSquare(int a,int b){ 4 return a*a+b*b; 5 } 6 double sumOfSquare(double a,double b){ 7 return a*a+b*b; 8 } 9 int main() 10 { 11 int m,n; 12 cout<<"Enter two integer:"; 13 cin>>m>>n; 14 cout<<"Their sum of square:"<<sumOfSquare(m,n)<<endl; 15 16 double x,y; 17 cout<<"Enter two real number:"; 18 cin>>x>>y; 19 cout<<"Their sum of square:"<<sumOfSquare(x,y)<<endl; 20 return 0; 21 }
Enter two integer:3 5 Their sum of square:34 Enter two real number:2.3 5.8 Their sum of square:38.93
第四章 类与对象
4.1 面向对象程序设计的基本特点
(1)抽象
是对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程。包括数据抽象和行为抽象(功能抽象)。
例:时钟
数据抽象:int hour, int minute, int second
功能抽象:showTime(), setTime()
(2)封装
将抽象得到的数据和行为(或功能)相结合,形成一个有机整体,也就是将数据与操作数据的函数代码进行有机结合,形成“类”,其中的数据和函数都是类的成员。
class Clock //class关键字 类名 { //边界 public : //外部接口 void setTime(int newH,int newM,int newS);//行为,代码成员 void showTime(); //行为,代码成员 private : //特定的访问权限 int hour, int minute,int second; //属性,数据成员 }; //边界
声明为public的两个函数为类提供了外部接口,外界只能通过这个接口来与Clock类发生联系。声明为private的3个整形数据是本类的私有数据,外部无法直接访问。
(3)继承
在一般概念的基础上,派生出特殊概念,使得一般概念中的属性和行为可以被特殊概念共享。
C++语言中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的说明。
(4)多态
指一段程序能够处理多种类型对象的能力。在C++语言中,这种多态可以通过强制多态,重载多态,类型参数化多态,包含多态4种形式来实现。
4.2 类和对象
4.2.1 类的定义
class 类名称 { public: 外部接口 protected: 保护型成员 private: 私有成员 } ;
在类中可以只声明函数的原型,函数的实现(即函数体)可以在类外定义。
4.2.2 类成员的访问控制
类的成员包括数据成员和函数成员,分别描述问题的属性和行为。访问控制属性有:公有类型(public)、私有类型(private)和保护类型(protected)。公有类型成员定义了类的外部接口,用public关键字声明,在类外只能访问类的公有成员。关键字private后面声明的就是类的私有成员,只能被本类的成员函数访问,(一个类的数据成员都应该声明为私有成员)。保护类型成员与私有成员的性质相似,差别在于继承过程中对产生的新类影响不同。
4.2.3 对象
如果将类看作自定义的类型,那么类的对象就可以看成是该类型的变量。声明一个对象和声明 一个一般变量相同,采用 类名 对象名; 例如Clock myClock ;就声明了一个时钟类型的对象myClock。(对象所占据的内存空间知识用于存放数据成员)。
定义了类及其对象,就可以访问对象的成员。用“.”操作符进行访问。例如myClock.showTime() 在类的外部只能访问公有成员;在类的成员函数中,可以访问到类的全部成员。
4.2.4 类的成员函数
描述的是类的行为、是对封装数据进行操作的方法。
(1)成员函数的实现:函数的原型声明要写在类体之中,而函数的具体实现是写在类定义之外的。与普通函数不同的是,类的成员函数名需要用类名来限制,具体形式为:
返回值类型 类名::函数成员名(参数表)
{
函数体
}
void Clock::setTime(int newH,int newM,int newS){ hour=newH; minute=newM; second=newS; } void Clock::showTime(){ cout<<hour<<":"<<minute<<":"<<second<<endl; }
(2)成员函数调用中的目的对象:例如使用myClock.showTime()调用函数时,myClock就是这一调用过程中的目的对象。在成员函数中可以不使用“.”操作符而直接引用目的对象的数据成员。在成员函数中引用其他对象的属性和调用其他对象的方法时,都需要使用“.”操作符。既可以访问目的对象的私有成员,也可以访问当前类其他对象的私有成员。
(3)带默认形参值的成员函数:默认值要写在类定义中,而不能写在类定义之外的函数实现中
(4)内联成员函数:如果有的函数成员被频繁调用且较简单,这个函数也可以定义为内联函数。与第三章相同,内联成员函数的函数体也会在编译时被插入到每一个调用它的地方。分为隐式声明和显示声明。
//隐式声明:将函数体直接放在类体内 class Clock{ public : void setTime(int newH,int newM,int newS); void showTime(){ cout<<hour<<":"<<minute<<":"<<second<<endl; } private: int hour,minute,sencond; }; //显示声明:在函数体实现时使用关键字inline inline void Clock::showTime(){ cout<<hour<<":"<<minute<<":"<<second<<endl; }
时钟类的完整程序
1 #include<iostream> 2 using namespace std; 3 class Clock{ //时钟类的定义 4 public : //外部接口,公有成员函数 5 void setTime(int newH=0,int newM=0,int newS=0); 6 void showTime(); 7 private: 8 int hour,minute,second; //私有数据成员 9 }; 10 //时钟类成员函数的具体实现 11 void Clock::setTime(int newH,int newM,int newS){ 12 hour=newH; 13 minute=newM; 14 second=newS; 15 } 16 inline void Clock::showTime(){ 17 cout<<hour<<":"<<minute<<":"<<second<<endl; 18 } 19 20 int main() 21 { 22 Clock myClock; //定义对象myClock 23 cout<<"First time set and output:"<<endl; 24 myClock.setTime(); //设置时间为默认值 25 myClock.showTime(); 26 cout<<"Second time set and output:"<<endl; 27 myClock.setTime(8,30,30); //设置时间 28 myClock.showTime(); 29 return 0; 30 }
First time set and output: 0:0:0 Second time set and output: 8:30:30
4.3 构造函数和析构函数
处理对象的初始化和清理工作
4.3.1 构造函数:其函数名与类名相同,且没有返回值,通常被声明为公有函数。只要类中有构造函数,在创建新对象时将会被自动调用;若没有,编译器会自动生成一个隐含的默认构造函数(参数列表、函数体为空)。
class Clock { public: Clock(){} //编译系统生成的隐含的默认构造函数 ... };