1.内联函数
1.1 内联函数基本概念
在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真
正的函数。内联函数具有普通函数的所有行为。唯一不同之处在于内联函数会在适当
的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用
内联函数。
在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。但是必须注
意必须配合函数体的定义结合在一起,否则编译器将它作为普通函数来对待。
内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省去了函数调用
时候的压栈,跳转,返回的开销。我们可以理解为内联函数是以空间换时间。
1.2 类内部的内联函数
为了定义内联函数,通常必须在函数定义前面放一个inline关键字。但是在类内部
定义内联函数时并不是必须的。任何在类内部定义的函数自动成为内联函数。
1.3 内联函数和编译器
对于任何类型的函数,编译器会将函数类型(包括函数名字,参数类型,返回值类型)
放入到符号表中。同样,当编译器看到内联函数,并且对内联函数体进行分析没有发现
错误时,也会将内联函数放入符号表。
当调用一个内联函数的时候,编译器首先确保传入参数类型是正确匹配的,或者如果
类型不能完全匹配,但是可以将其转换为正确类型,并且返回值在目标表达式里匹配正
确类型,或者可以转换为目标类型,内联函数就会直接替换函数调用,这就消除了函数
调用的开销。假如内联函数是成员函数,对象this指针也会被放入合适位置。
注:
c++内联编译会有一些限制,以下情况编译器可能考虑不会将函数进行内联编译:
1.不能存在任何形式的循环语句
2.不能存在过多的条件判断语句
3.函数体不能过于庞大
4.不能对函数进行取址操作
内联仅仅只是给编译器一个建议,编译器不一定会接受这种建议,如果你没有将函
数声明为内联函数,那么编译器也可能将此函数做内联编译。一个好的编译器将会内
联小的、简单的函数。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#define ADD(x,y) ((x)+(y))
inline int Add ( int x, int y)
{
return x + y;
}
void test01 ( )
{
int a = 10 ;
int b = 20 ;
cout << ADD ( a, b) << endl;
cout << Add ( a, b) << endl;
}
#define MyTEST(x,y) ((x)<(y)?(x):(y))
inline int func2 ( int x, int y)
{
return x < y ? x : y;
}
void test02 ( )
{
int a = 1 ;
int b = 3 ;
cout << func2 ( a, b) << endl;
}
int main ( )
{
test02 ( ) ;
system ( "pause" ) ;
return 0 ;
}
2.函数的参数
2.1 函数的默认参数
c++在声明函数原型的时可为一个或者多个参数指定默认(缺省)的参数值,当函数
调用的时候如果没有指定这个值,编译器会自动用默认值代替,并且,在设定了默认
参数之后,这个参数之后的参数都要提前设定默认值。
2.2 函数的占位参数
c++在声明函数时,可以设置占位参数。占位参数只有参数类型声明,而没有参数
名声明。一般情况下,在函数体内部无法使用占位参数。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
int test01 ( int a, int b = 10 )
{
return a + b;
}
int test02 ( int a, int b = 10 , int c = 0 , int d = 10 )
{
return a + b + c + d;
}
void test03 ( int a, int b ) ;
void test03 ( int a, int b = 0 )
{
cout << "test03调用" << endl;
}
void test04 ( int a, int = 10 )
{
cout << "test04()的调用" << endl;
}
int main ( )
{
test04 ( 10 ) ;
system ( "pause" ) ;
return 0 ;
}
3.函数重载
3.1 函数重载基本语法
实现函数重载的条件:
1.同一个作用域
2.参数个数不同
3.参数类型不同
4.参数顺序不同
注: 函数重载和默认参数一起使用,需要额外注意二义性问题的产生。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int add ( int a, int b)
{
return a + b;
}
int add ( int a, double b)
{
return a + b;
}
int add ( double a, double b)
{
return a + b;
}
int add ( double a, int b)
{
return a + b;
}
void myFunc ( int a, int b = 0 )
{
cout << "myFunc(int a,int b = 0)的调用" << endl;
}
void myFunc ( int a)
{
cout << "myFunc(int a)的调用" << endl;
}
void myFunc ( )
{
cout << "myFunc()的调用" << endl;
}
int main ( )
{
int a = 10 ;
double b = 20 ;
cout << add ( a, a) << endl;
cout << add ( a, b) << endl;
cout << add ( b, b) << endl;
cout << add ( b, a) << endl;
myFunc ( a, a) ;
system ( "pause" ) ;
return 0 ;
}
3.2 函数重载实现原理
编译器为了实现函数重载,用不同的参数类型来修饰不同的函数名,比如void func();
编译器可能会将函数名修饰成_func,当编译器碰到void func(int x),编译器可能将函数
名修饰为func_int,当编译器碰到void func(int x,char c),编译器可能会将函数名修饰为
_func_int_char。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int add ( int a, int b)
{
return a + b;
}
int add ( int a, double b)
{
return a + b;
}
int add ( double a, double b)
{
return a + b;
}
int add ( double a, int b)
{
return a + b;
}
void myFunc ( int a, int b = 0 )
{
cout << "myFunc(int a,int b = 0)的调用" << endl;
}
void myFunc ( int a)
{
cout << "myFunc(int a)的调用" << endl;
}
void myFunc ( )
{
cout << "myFunc()的调用" << endl;
}
int main ( )
{
int a = 10 ;
double b = 20 ;
cout << add ( a, a) << endl;
cout << add ( a, b) << endl;
cout << add ( b, b) << endl;
cout << add ( b, a) << endl;
myFunc ( a, a) ;
system ( "pause" ) ;
return 0 ;
}
3.3 在C++中调用C语言程序注意事项
在C++中要是调用C语言的函数的话,一般都不能正常编译通过,之所以会出
现这种问题,就是因为编译器在函数编译之后,会将函数名字改为上述的形式,在C++
和C中编写的函数函数名是不同的,因此当编译器在C++的环境下使用,C语言编写的函
数的话,编译器就无法正确识别所需的函数,因此就需要一些特殊手段。
#define _crt_secure_no_warnings
#include <iostream>
#include <string>
using namespace std;
int main ( )
{
system ( "pause" ) ;
return 0 ;
}
4. 类和对象
4.1 C和C++中struct区别
1.c语言struct只有变量
2.c++语言struct 既有变量,也有函数
struct和class的区别:
class默认访问权限为private,struct默认访问权限为public.
4.2 类的封装
1.把变量(属性)和函数(操作)合成一个整体,封装在一个类中
2. 对变量和函数进行访问控制
访问权限:
1.在类的内部(作用域范围内),没有访问权限之分,所有成员可以相互访问
2.在类的外部(作用域范围外),访问权限才有意义:public,private,protected
在类的外部,只有public修饰的成员才能被访问,在没有涉及继承与派生时,
private和protected是同等级的,外部不允许访问。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Maker
{
public :
void set ( string name, int id)
{
this - > id = id;
this - > name = name;
}
void printMaker ( )
{
cout << "姓名:" << this - > name << "\n序号:" << this - > id<< endl;
}
private :
int id;
string name;
} ;
void test01 ( )
{
Maker m;
m. set ( "张三" , 1 ) ;
m. printMaker ( ) ;
}
int main ( )
{
test01 ( ) ;
system ( "pause" ) ;
return 0 ;
}
4.3将成员变量设置为private的作用:
1.可赋予客户端访问数据的一致性。
如果成员变量不是public,客户端唯一能够访问对象的方法就是通过成员函数。
如果类中所有public权限的成员都是函数,客户在访问类成员时只会默认访问函数,
不需要考虑访问的成员需不需要添加()。
2.可细微划分访问控制。
使用成员函数可使得我们对变量的控制处理更加精细。如果我们让所有的成员变
量为public,每个人都可以读写它。如果我们设置为private,我们可以实现“不准访
问”、“只读访问”、“读写访问”,甚至你可以写出“只写访问”。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Maker
{
public :
void initMaker ( )
{
this - > name = " " ;
this - > age = 0 ;
}
void scanfName ( string name)
{
this - > name = name;
}
void printName ( )
{
cout << "姓名:" << this - > name << endl;
}
void scanfAge ( int age)
{
if ( age >= 0 && age <= 100 )
{
this - > age = age;
return ;
}
}
void printAge ( )
{
cout << "年龄:" << this - > age << endl;
}
private :
int age;
string name;
} ;
void test01 ( )
{
Maker m;
m. initMaker ( ) ;
m. printName ( ) ;
m. printAge ( ) ;
m. scanfName ( "张三" ) ;
m. scanfAge ( 18 ) ;
m. printName ( ) ;
m. printAge ( ) ;
}
int main ( )
{
test01 ( ) ;
system ( "pause" ) ;
return 0 ;
}
5.案例
5.1 设计立方体类(Cube),求出立方体的面积( 2*a*b + 2*a*c + 2*b*c )和体积( a * b * c),
分别用全局函数和成员函数判断两个立方体是否相等。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Cude
{
public :
void initCube ( )
{
this - > longth = 0 ;
this - > length = 0 ;
this - > height = 0 ;
}
void setLongth ( int longth)
{
this - > longth = longth;
}
void setLength ( int length)
{
this - > length = length;
}
void setHeight ( int height)
{
this - > height = height;
}
int squareCube ( )
{
return 2 * ( this - > height + this - > length + this - > longth) ;
}
int volumeCube ( )
{
return this - > height * this - > length * this - > longth;
}
int comPareCube ( Cude c1)
{
if ( this - > longth == c1. longth && this - > height == c1. height && this - > length == c1. length)
return 1 ;
else
return 0 ;
}
private :
int longth;
int length;
int height;
} ;
int compareSquareCube ( Cude c1, Cude c2)
{
if ( c1. squareCube ( ) == c2. squareCube ( ) )
return 1 ;
return 0 ;
}
int comparevolumeCube ( Cude c1, Cude c2)
{
if ( c1. volumeCube ( ) == c2. volumeCube ( ) )
return 1 ;
return 0 ;
}
void test01 ( )
{
Cude c1;
Cude c2;
c1. initCube ( ) ;
c1. setHeight ( 30 ) ;
c1. setLength ( 20 ) ;
c1. setLongth ( 10 ) ;
c2. initCube ( ) ;
c2. setLongth ( 10 ) ;
c2. setLength ( 20 ) ;
c2. setHeight ( 30 ) ;
if ( c1. comPareCube ( c2) )
cout << "相等!" << endl;
else
cout << "不相等!" << endl;
if ( compareSquareCube ( c1, c2) )
cout << "面积相等!" << endl;
else
cout << "面积不相等!" << endl;
if ( comparevolumeCube ( c1, c2) )
cout << "体积相等!" << endl;
else
cout << "体积不相等!" << endl;
}
int main ( )
{
test01 ( ) ;
system ( "pause" ) ;
return 0 ;
}
5.2 点和圆的关系
设计一个圆形类(AdvCircle),和一个点类(Point),计算点和圆的关系。
假如圆心坐标为x0, y0, 半径为r,点的坐标为x1, y1:
1)点在圆上:(x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) == r*r
2)点在圆内:(x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) < r*r
3)点在圆外:(x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) > r*r
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Point
{
public :
void initPoint ( )
{
this - > p_x = 0 ;
this - > p_y = 0 ;
}
void setX ( int x)
{
p_x = x;
}
void setY ( int y)
{
p_y = y;
}
int getX ( )
{
return this - > p_x;
}
int getY ( )
{
return this - > p_y;
}
private :
int p_x;
int p_y;
} ;
class Circle
{
public :
void initCircle ( )
{
c_point. setX ( 0 ) ;
c_point. setY ( 0 ) ;
c_r = 0 ;
}
void setCircle ( int x, int y, int r)
{
c_point. setX ( x) ;
c_point. setY ( y) ;
c_r = r;
}
int compareCirPoi ( Point p1)
{
if ( ( ( this - > c_point. getX ( ) - p1. getX ( ) ) * ( this - > c_point. getX ( ) - p1. getX ( ) ) + ( this - > c_point. getY ( ) - p1. getY ( ) ) * ( this - > c_point. getY ( ) - p1. getY ( ) ) ) == ( this - > c_r * this - > c_r) )
return 0 ;
if ( ( ( this - > c_point. getX ( ) - p1. getX ( ) ) * ( this - > c_point. getX ( ) - p1. getX ( ) ) + ( this - > c_point. getY ( ) - p1. getY ( ) ) * ( this - > c_point. getY ( ) - p1. getY ( ) ) ) > ( this - > c_r * this - > c_r) )
return 1 ;
else
return - 1 ;
}
private :
Point c_point;
int c_r;
} ;
void test01 ( )
{
Point p1;
Circle c1;
p1. initPoint ( ) ;
p1. setX ( 10 ) ;
p1. setY ( 10 ) ;
c1. initCircle ( ) ;
c1. setCircle ( 10 , 20 , 5 ) ;
if ( c1. compareCirPoi ( p1) == 0 )
cout << "在圆上!" << endl;
else if ( c1. compareCirPoi ( p1) == 1 )
cout << "在圆外!" << endl;
else
cout << "在圆内!" << endl;
}
int main ( )
{
test01 ( ) ;
system ( "pause" ) ;
return 0 ;
}