第三章 函数
3-1 C++中的函数是什么?什么叫主调函数,什么叫被调函数,二者之间有什么关系?如何调用一个函数?
解:
一个较为复杂的系统往往需要划分为若干子系统,高级语言中的子程序就是用来实现这种模块划分的。C和C++语言中的子程序就体现为函数。调用其它函数的函数被称为主调函数,被其它函数调用的函数称为被调函数。一个函数很可能既调用别的函数又被另外的函数调用,这样它可能在某一个调用与被调用关系中充当主调函数,而在另一个调用与被调用关系中充当被调函数。
调用函数之前先要声明函数原型。按如下形式声明:
类型标识符 被调函数名 (含类型说明的形参表);
声明了函数原型之后,便可以按如下形式调用子函数:
函数名(实参列表)
3-2 观察下面程序的运行输出,与你设想的有何不同?仔细体会引用的用法。
源程序:
#include <iostream.h>
int main()
{
int intOne;
int &rSomeRef = intOne;
intOne = 5;
cout << "intOne:\t\t" << intOne << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
int intTwo = 8;
rSomeRef = intTwo; // not what you think!
cout << "\nintOne:\t\t" << intOne << endl;
cout << "intTwo:\t\t" << intTwo << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
return 0;
}
程序运行输出:
intOne: 5
rSomeRef: 5
intOne: 8
intTwo: 8
rSomeRef: 8
3-3 比较值调用和引用调用的相同点与不同点。
解:
值调用是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。这一过程是参数值的单向传递过程,一旦形参获得了值便与实参脱离关系,此后无论形参发生了怎样的改变,都不会影响到实参。
引用调用将引用作为形参,在执行主调函数中的调用语句时,系统自动用实参来初始化形参。这样形参就成为实参的一个别名,对形参的任何操作也就直接作用于实参。
3-4 什么叫内联函数?它有哪些特点?
解:
定义时使用关键字 inline的函数叫做内联函数;
编译器在编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销;
内联函数体内不能有循环语句和switch语句;
内联函数的定义必须出现在内联函数第一次被调用之前;
对内联函数不能进行异常接口声明;
3-5 函数原型中的参数名与函数定义中的参数名以及函数调用中的参数名必须一致吗?
解:
不必一致,所有的参数是根据位置和类型而不是名字来区分的。
3-6 重载函数时通过什么来区分?
解:
重载的函数的函数名是相同的,但它们的参数的个数和数据类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数。
3-7 编写函数,参数为两个unsigned short int型数,返回值为第一个参数除以第二个参数的结果,数据类型为short
int;如果第二个参数为0,则返回值为-1。在主程序中实现输入输出。
解:
源程序:
#include <iostream.h>
short int Divider(unsigned short int a, unsigned short int b)
{
if (b == 0)
return -1;
else
return a/b;
}
typedef unsigned short int USHORT;
typedef unsigned long int ULONG;
int main()
{
USHORT one, two;
short int answer;
cout << "Enter two numbers.\n Number one: ";
cin >> one;
cout << "Number two: ";
cin >> two;
answer = Divider(one, two);
if (answer > -1)
cout << "Answer: " << answer;
else
cout << "Error, can't divide by zero!";
return 0;
}
程序运行输出:
Enter two numbers.
Number one:8
Number two:2
Answer: 4
3-8 编写函数把华氏温度转换为摄氏温度,公式为:C = (F - 32) * 5/9; 在主程序中提示用户输入一个华氏温度,转化后输出相应的摄氏温度。
解:
源程序见"实验指导"部分实验三
3-9 编写函数判断一个数是否是质数,在主程序中实现输入、输出。
解:
#include <iostream.h>
#include <math.h>
int prime(int i); //判一个数是否是质数的函数
void main()
{
int i;
cout << "请输入一个整数:";
cin >> i;
if (prime(i))
cout << i << "是质数." << endl;
else
cout << i << "不是质数." << endl;
}
int prime(int i)
{
int j,k,flag;
flag = 1;
k = sqrt(i);
for (j = 2; j <= k; j++)
{
if(i%j == 0)
{
flag = 0;
break;
}
}
if (flag)
return 1;
else
return 0;
}
程序运行输出:
请输入一个整数:1151
1151是质数.
3-10 编写函数求两个整数的最大公约数和最小公倍数。
解:
源程序:
#include <iostream.h>
#include <math.h>
int fn1(int i,int j); //求最大公约数的函数
void main()
{
int i,j,x,y;
cout << "请输入一个正整数:";
cin >> i ;
cout << "请输入另一个正整数:";
cin >> j ;
x = fn1(i,j);
y = i * j / x;
cout << i << "和" << j << "的最大公约数是:" << x << endl;
cout << i << "和" << j << "的最小公倍数是:" << y << endl;
}
int fn1(int i, int j)
{
int temp;
if (i < j)
{
temp = i;
i = j;
j = i;
}
while(j != 0)
{
temp = i % j;
i = j;
j = temp;
}
return i;
}
程序运行输出:
请输入一个正整数:120
请输入另一个正整数:72
120和72的最大公约数是:24
120和72的最小公倍数是:360
3-11 什么叫作嵌套调用?什么叫作递归调用?
解:
函数允许嵌套调用,如果函数1调用了函数2,函数2再调用函数3,便形成了函数的嵌套调用。
函数可以直接或间接地调用自身,称为递归调用。
3-12 在主程序中提示输入整数n,编写函数用递归的方法求1 + 2 + … + n的值。
解:
#include <iostream.h>
#include <math.h>
int fn1(int i);
void main()
{
int i;
cout << "请输入一个正整数:";
cin >> i ;
cout << "从1累加到" <<i << "的和为:" << fn1(i) << endl;
}
int fn1(int i)
{
if (i == 1)
return 1;
else
return i + fn1(i -1);
}
程序运行输出:
请输入一个正整数:100
从1累加到100的和为:5050
3-13 编写递归函数GetPower(int x, int y)计算x的y次幂, 在主程序中实现输入输出。
解:
源程序:
#include <iostream.h>
long GetPower(int x, int y);
int main()
{
int number, power;
long answer;
cout << "Enter a number: ";
cin >> number;
cout << "To what power? ";
cin >> power;
answer = GetPower(number,power);
cout << number << " to the " << power << "th power is " <<answer << endl;
return 0;
}
long GetPower(int x, int y)
{
if(y == 1)
return x;
else
return (x * GetPower(x,y-1));
}
程序运行输出:
Enter a number: 3
To what power? 4
3 to the 4th power is 81
3-14 用递归的方法编写函数求Fibonacci 级数,公式为fib(n) = fib(n-1) + fib(n-2),n>2;
fib(1) = fib(2) = 1;观察递归调用的过程。
解:
源程序见"实验指导"部分实验三
3-15 用递归的方法编写函数求n阶勒让德多项式的值,在主程序中实现输入、输出;
解:
#include <iostream.h>
float p(int n, int x);
void main()
{
int n,x;
cout << "请输入正整数n:";
cin >> n;
cout << "请输入正整数x:";
cin >> x;
cout << "n = " << n << endl;
cout << "x = " << x << endl;
cout << "P" << n << "(" << x << ") = " << p(n,x) << endl;
}
float p(int n, int x)
{
if (n == 0)
return 1;
else if (n == 1)
return x;
else
return ((2*n-1)*x*p(n-1,x) - (n-1)*p(n-2,x)) /n ;
}
程序运行输出:
请输入正整数n:1
请输入正整数x:2
n = 1
x = 2
P1(2) = 2
请输入正整数n:3
请输入正整数x:4
n = 3
x = 4
P3(4) = 154
3-16 使用模板函数实现Swap( x, y ),函数功能为交换x、y的值。
解:
源程序:
#include <iostream.h>
template <typename T> void swap(T &x, T &y)
{
T z;
z = x;
x = y;
y = z;
}
void main()
{
int j = 1, k = 2;
double v = 3.0, w = 4.0;
cout << "j = " <<j << " k = " << k << endl;
cout << "v = " <<v << " w = " << w << endl;
swap(j, k); //int
swap(v, w); //double
cout << "After swap:" << endl;
cout << "j = " <<j << " k = " << k << endl;
cout << "v = " <<v << " w = " << w << endl;
}
程序运行输出:
j = 1 k = 2
v = 3.14 w = 4.35
After swap:
j = 2 k = 1
v = 4.35 w = 3.14
第 四 章 类
4-1 解释public和private的作用,公有类型成员与私有类型成员有些什么区别?
解:
公有类型成员用public关键字声明,公有类型定义了类的外部接口;私有类型的成员用private关键字声明,只允许本类的函数成员来访问,而类外部的任何访问都是非法的,这样,私有的成员就整个隐蔽在类中,在类的外部根本就无法看到,实现了访问权限的有效控制。
4-2 protected关键字有何作用?
解:
protected用来声明保护类型的成员,保护类型的性质和私有类型的性质相似,其差别在于继承和派生时派生类的成员函数可以访问基类的保护成员。
4-3 构造函数和析构函数有什么作用?
解:
构造函数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态,使此对象具有区别于彼对象的特征,完成的就是是一个从一般到具体的过程,构造函数在对象创建的时候由系统自动调用。
析构函数与构造函数的作用几乎正好相反,它是用来完成对象被删除前的一些清理工作,也就是专门作扫尾工作的。一般情况下,析构函数是在对象的生存期即将结束的时刻由系统自动调用的,它的调用完成之后,对象也就消失了,相应的内存空间也被释放。
4-4 数据成员可以为公有的吗?成员函数可以为私有的吗?
解:
可以,二者都是合法的。数据成员和成员函数都可以为公有或私有的。但数据成员最好定义为私有的。
4-5 已知class A中有数据成员int a,如果定义了A的两个对象A1、A2,它们各自的数据成员a的值可以不同吗?
解:
可以,类的每一个对象都有自己的数据成员。
4-6 什么叫做拷贝构造函数?拷贝构造函数何时被调用?
解:
拷贝构造函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类的对象的引用,其作用是使用一个已经存在的对象,去初始化一个新的同类的对象。在以下三种情况下会被调用:在当用类的一个对象去初始化该类的另一个对象时;如果函数的形参是类对象,调用函数进行形参和实参结合时;如果函数的返回值是类对象,函数调用完成返回时;
4-7 拷贝构造函数与赋值运算符(=)有何不同?
解:
赋值运算符(=)作用于一个已存在的对象;而拷贝构造函数会创建一个新的对象。
4-8 定义一个Dog 类,包含的age、weight等属性,以及对这些属性操作的方法。实现并测试这个类。
解:
源程序:
#include <iostream.h>
class Dog
{
public:
Dog (int initialAge = 0, int initialWeight = 5);
~Dog();
int GetAge() { return itsAge;} // inline!
void SetAge (int age) { itsAge = age;} // inline!
int GetWeight() { return itsWeight;} // inline!
void SetWeight (int weight) { itsAge = weight;} // inline!
private:
int itsAge, itsWeight;
};
Dog::Dog(int initialAge, int initialWeight)
{
itsAge = initialAge;
itsWeight = initialWeight;
}
Dog::~Dog() //destructor, takes no action
{
}
int main()
{
Dog Jack(2,10);
cout << "Jack is a Dog who is " ;
cout << Jack.GetAge() << " years old and";
cout << Jack.GetWeight() << " pounds weight.\n";
Jack.SetAge(7);
Jack.SetWeight(20);
cout << "Now Jack is " ;
cout << Jack.GetAge() << " years old and";
cout << Jack.GetWeight() << " pounds weight.";
return 0;
}
程序运行输出:
Jack is a Dog who is 2 years old and 10 pounds weight.
Now Jack is 7 years old 20 pounds weight.
4-9 设计并测试一个名为Rectangle的矩形类,其属性为矩形的左下角与右上角两个点的坐标,能计算矩形的面积。
解:
源程序:
#include <iostream.h>
class Rectangle
{
public:
Rectangle (int top, int left, int bottom, int right);
~Rectangle () {}
int GetTop() const { return itsTop; }
int GetLeft() const { return itsLeft; }
int GetBottom() const { return itsBottom; }
int GetRight() const { return itsRight; }
void SetTop(int top) { itsTop = top; }
void SetLeft (int left) { itsLeft = left; }
void SetBottom (int bottom) { itsBottom = bottom; }
void SetRight (int right) { itsRight = right; }
int GetArea() const;
private:
int itsTop;
int itsLeft;
int itsBottom;
int itsRight;
};
Rectangle::Rectangle(int top, int left, int bottom, int right)
{
itsTop = top;
itsLeft = left;
itsBottom = bottom;
itsRight = right;
}
int Rectangle::GetArea() const
{
int Width = itsRight-itsLeft;
int Height = itsTop - itsBottom;
return (Width * Height);
}
int main()
{
Rectangle MyRectangle (100, 20, 50, 80 );
int Area = MyRectangle.GetArea();
cout << "Area: " << Area << "\n";
return 0;
}
程序运行输出:
Area: 3000
Upper Left X Coordinate: 20
4-10
设计一个用于人事管理的People(人员)类。考虑到通用性,这里只抽象出所有类型人员都具有的属性:number(编号)、sex(性别)、birthday(出生日期)、id(身份证号)等等。其中"出生日期"定义为一个"日期"类内嵌子对象。用成员函数实现对人员信息的录入和显示。要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数、带缺省形参值的成员函数、聚集。
解:
本题用作实验四的选做题,因此不给出答案。
4-11 定义一个矩形类,有长、宽两个属性,有成员函数计算矩形的面积
解:
#include <iostream.h>
class Rectangle
{
public:
Rectangle(float len, float width)
{
Length = len;
Width = width;
}
~Rectangle(){};
float GetArea() { return Length * Width; }
float GetLength() { return Length; }
float GetWidth() { return Width; }
private:
float Length;
float Width;
};
void main()
{
float length, width;
cout << "请输入矩形的长度:";
cin >> length;
cout << "请输入矩形的宽度:";
cin >> width;
Rectangle r(length, width);
cout << "长为" << length << "宽为" << width << "的矩形的面积为:"
<< r.GetArea () << endl;
}
程序运行输出:
请输入矩形的长度:5
请输入矩形的宽度:4
长为5宽为4的矩形的面积为:20
/*4-11-2 已有点类Point定义,定义一个矩形类,有左下角,右上角两个点,面积,周长属性,面积,周长由左下角,右上角两个点决定;有成员函数有(1)构造函数(2)返回矩形的面积(3)返回周长
(提示:用类组合实现)
解:
*/
#include <iostream.h>
class Point
{
public:
Point(int xx=0,int yy=0){X=xx; Y=yy;}//构造函数
Point(Point& p);
int GetX() {return X;}
int GetY() {return Y;}
private:
int X,Y;
};
Point::Point (Point& p)
{ X=p.X;
Y=p.Y;
//cout<<"拷贝构造函数被调用"<<endl;
}
class Rectangle
{public:
Rectangle(Point xp1, Point xp2);//构造函数
Rectangle(Rectangle &);//拷贝构造函数
float getarea(){return area;}
float getlen(){return len;}
private:
Point p1,p2;
float area,len;
};
Rectangle::Rectangle(Point xp1,Point xp2):p1(xp1),p2(xp2)
{ float h=p2.GetY()-p1.GetY();
float w=p2.GetX()-p1.GetX();
area=h*w;
len=2*(h+w);
}
Rectangle::Rectangle(Rectangle &Rect):p1(Rect.p1),p2(Rect.p2)
{ area=Rect.area;
len=Rect.len;
}
void main()
{
int x,y;
cout << "请输入矩形的左下角点坐标p1的x y坐标:";
cin >> x>>y; Point myp1(x,y);
cout << "请输入矩形的右上角点坐标p2的x y坐标:";
cin >> x>>y; Point myp2(x,y);
Rectangle Rect1(myp1, myp2);
Rectangle Rect2(Rect1);
cout << "第一个矩形的面积为:" << Rect1.getarea() << " 周长为:" << Rect1.getlen()<<endl;
cout << "第二个矩形的面积为:" << Rect2.getarea() << " 周长为:" << Rect2.getlen()<<endl;
}
4-12 定义一个"数据类型" datatype类,能处理包含字符型、整型、浮点型三种类型的数据,给出其构造函数。
解:
#include <iostream.h>
class datatype{
enum{
character,
integer,
floating_point
} vartype;
union
{
char c;
int i;
float f;
};
public:
datatype(char ch) {
vartype = character;
c = ch;
}
datatype(int ii) {
vartype = integer;
i = ii;
}
datatype(float ff) {
vartype = floating_point;
f = ff;
}
void print();
};
void datatype::print() {
switch (vartype) {
case character:
cout << "字符型: " << c << endl;
break;
case integer:
cout << "整型: " << i << endl;
break;
case floating_point:
cout << "浮点型: " << f << endl;
break;
}
}
void main() {
datatype A('c'), B(12), C(1.44F);
A.print();
B.print();
C.print();
}
程序运行输出:
字符型: c
整型: 12
浮点型: 1.44
4-13 定义一个Circle类,有数据成员半径Radius,成员函数GetArea(),计算圆的面积,构造一个Circle的对象进行测试。
解:
#include <iostream.h>
class Circle
{
public:
Circle(float radius){ Radius = radius;}
~Circle(){}
float GetArea() { return 3.14 * Radius * Radius; }
private:
float Radius;
};
void main()
{
float radius;
cout << "请输入圆的半径:";
cin >> radius;
Circle p(radius);
cout << "半径为" << radius << "的圆的面积为:" << p.GetArea ()
<< endl;
}
程序运行输出:
请输入圆的半径:5
半径为5的圆的面积为:78.5
4-14 定义一个tree类,有成员ages,成员函数grow(int years)对ages加上years,age()显示tree对象的ages的值。
解:
#include <iostream.h>
class Tree {
int ages;
public:
Tree(int n=0);
~Tree();
void grow(int years);
void age();
};
Tree::Tree(int n) {
ages = n;
}
Tree::~Tree() {
age();
}
void Tree::grow(int years) {
ages += years;
}
void Tree::age() {
cout << "这棵树的年龄为" << ages << endl;
}
void main()
{
Tree t(12);
t.age();
t.grow(4);
}
程序运行输出:
这棵树的年龄为12
这棵树的年龄为16