本文是谭浩强老师C++程序设计第三版第九章的习题笔记,主要设计类和对象的应用。
1. 构造函数和析构函数的作用是什么?什么时候需要自己定义构造函数和析构函数?
(1)构造函数:是一种特殊的成员函数,它来实现对象的初始化,它不光可以对数据成员进行赋值,还可以包含其他语句,如cout语句等。构造函数可以自己定义也可以由系统默认给出,当用户未定义构造函数时,系统会提供构造函数,只是该函数是空的,不起初始化作用;如果用户希望在建立对象时就能使用成员初值,就必须自己定义构造函数。
(2)析构函数:是与构造函数作用相反的函数,其作用并不是删除对象,二是在撤销对象占用存储空间之前完成一些清理工作,如释放资源,同时还可以用来执行“用户希望在最后一次使用对象之后所执行的任何操作”,如输出相关信息等。一般情况下,类的设计者应该在声明类的同时定义析构函数,以指定如何完成清理工作,若用户没有定义析构函数,系统也会自动生成,但是它只是徒有析构函数的名称和形式,其实什么操作都不执行,要想让析构函数完成任何工作,都需要在定义的析构函数中指定。
2. 分析下面的程序 写出其运行时的输出结果
#include
using namespace std;
class Date
{public:
Date(int,int,int);
Date(int,int);
Date(int);
Date();
void display();
private:
int month;
int day;
int year;
};
Date::Date(int m,int d,int y):month(m),day(d),year(y)
{ }
Date::Date(int m,int d):month(m),day(d)
{year=2005;}
Date::Date(int m):month(m)
{day=1;
year=2005;
}
Date::Date()
{month=1;
day=1;
year=2005;
}
void Date::display()
{cout<
分析方法:这是构造函数的重载问题,原则是,同名的构造函数具有不同的参数,系统按调用时的参数形式来判断调用的是哪个构造函数,因此,上述程序按照构造函数的形式相同的来赋初值,可以得到下述结果:
10/13/2005
12/30/2005
10/1/2005
1/1/2005
3. 如果将第2题中程序的第5行改为用默认参数,即Date(int=1,int=1,int=2005); 分析程序有无问题。上机编译,分析出错信息,修改程序使之能通过编译。要求保留上面一行给出的构造函数,同时能输出与第2题的程序相同的输出结果。
编译出错,原因是构造函数使用默认参数后就不能再使用重载的构造函数,否则就会出现歧义,函数不知道调用的是谁。
修改方法:删去所有重载部分即可。
#include
using namespace std;
class Date
{public:
Date(int=1,int=1,int=2005);
//Date(int,int);
//Date(int);
//Date();
void display();
private:
int month;
int day;
int year;
};
Date::Date(int m,int d,int y):month(m),day(d),year(y)
{ }
//Date::Date(int m,int d):month(m),day(d)
// {year=2005;}
//
//Date::Date(int m):month(m)
// {day=1;
// year=2005;
// }
//
//Date::Date()
// {month=1;
// day=1;
// year=2005;
// }
void Date::display()
{cout<
4. 建立一个对象数组,内放5个学生的数据(学号、成绩),用指针指向数组首元素,输出第1,3,5个学生的数据。
//建立一个对象数组,内放5个学生的数据(学号、成绩),用指针指向数组首元素,输出第1,3,5个学生的数据。
#include
using namespace std;
class Student
{
public:
Student(int n,float s):num(n),score(s){};
void display();
private:
int num;
float score;
};
void Student::display()
{cout<display();
return 0;
}
5. 建立一个对象数组,内放5个学生的数据(学号、成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出5个学生中成绩最高者,并输出其学号。
//建立一个对象数组,内放5个学生的数据(学号、成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出5个学生中成绩最高者,并输出其学号。
#include
using namespace std;
class Student
{
public:
Student(int n, float s):num(n),score(s){};
int max(Student *arr);
int num;
float score;
};
int Student::max(Student *arr)
{
float max_score=arr[0].score;
int k=0;
for(int i=1;i<5;i++)
if(arr[i].score>max_score) {max_score=arr[i].score;k=i;}
return(k);
}
int main()
{
Student stu[5] ={Student(101,78.5),Student(102,85.5),Student(103,98.5),Student(104,100.0),Student(105,95.5)};
int k;
k = stu[5].max(stu);
cout<
6. 阅读下面程序,分析其执行过程,写出输出结果。
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) {num=n;score=s;}
void display(){cout<
程序分析:第一次dispay执行的是stud的初始值,即101,78.5,然后经过change函数,将第二次的101,80.5传入了change,因此第二次展示的结构是101,80.5
因此输出结果是:
101 78.5
101 80.5
7. 将第6题的程序分别作以下修改,分析所修改部分的含义以及编译和运行的情况。
(1) 将main函数第2行改为const Student stud(101,78.5);
(2) 在(1)的基础上修改程序,使之能正常运行,用change函数修改数据成员num和score的值。
(3) 将main函数改为
int main( )
{Student stud(101,78.5);
Student *p=&stud;
p->display( );
p->change(101,80.5);
p->display( );
return 0;
其他部分仍同第6题的程序。
(4) 在(3)的基础上将main函数第3行改为const Student *p=&stud;
(5) 再把main函数第3行改为Student *const p=&stud;
程序分析:
(1)改变是Student变为了常对象,由常对象的性质,它只能调用对象中的常函数而不能调用普通函数,因此display()函数需改为常函数;同时由于在其生命周期内,对象中所有的数据成员不能被修改,因此change函数没有意义,可以去掉。
因此程序修改如下:
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) {num=n;score=s;}
//void display() {cout<
(2)若一定要修改常对象中的数字成员,除了将其成员函数变为const类型之外,还要将待修改的数据成员声明为mutable类,如 mutable int count; 即可改变常对象中的数据成员,程序修改如下:
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) const{num = n;score = s;}
//void display() {cout<
(3)第三小题的改法没有问题,是用指针指向对象的过程,程序正常运行,结果如下
101 78.5
101 80.5
(4)第四小题的改法是用了指向常对象的指针变量,对于它而言,只有用指针访问常对象期间它不可以被改变,而不用指针访问则可以被改变,因此修改如下:
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) {num = n;score = s;}
//void display() {cout<display( );
stud.change(101,80.5);
p->display( );
return 0;
}
(5)第四小题的改法是将p定义为指向对象的常指针,这种情况下,指针的值不可改变,也就是指向不能改变,但是可以改变指向对象的值,在题中,这种修改只是改变了stud的值,而p指向stud的指向始终没变,因此这种情况下程序正常运行,完整代码如下:
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) {num = n;score = s;}
//void display() {cout<display( );
p ->change(101,80.5);
p->display( );
return 0;
}
8. 修改第6题的程序,增加一个fun函数,改写main函数。在main函数中调用fun函数,在fun函数中调用change和display函数。在fun函数中使用对象的引用(Student &)作为形参。
这个问题考的是对象的应用,也就是用变量的别名来表示它,此时在fun的形参里是对象Student的引用(别名),而在实参里则是类对象,程序如下:
#include
using namespace std;
class Student
{public:
Student(int n,float s):num(n),score(s){}
void change(int n,float s) {num=n;score=s;}
void display() {cout<
9. 商店销售某一商品,商店每天公布统一的折扣(discount)。同时允许销售人员在销售时灵活掌握售价(price),在此基础上,对一次购10件以上者,还可以享受9.8折优惠。现已知当天3名销货员的销售情况为:
销货员号(num) 销货件数(quantity) 销货单价(price)
101 5 23.5
102 12 24.56
103 100 21.5
请编程序,计算出当日此商品的总销售款sum,以及每件商品的平均售价。要求用静态数据成员和静态成员函数。
#include
using namespace std;
class Product
{public:
Product(int n,int q,float p):num(n),quantity(q),price(p){};
void total();
static float average();
static void display();
private:
int num;
int quantity;
float price;
static float discount;
static float sum;
static int n;
};
void Product::total()
{float rate=1.0;
if(quantity>10) rate=0.98*rate;
sum=sum+quantity*price*rate*(1-discount);
n=n+quantity;
}
void Product::display()
{cout<
10. 将例9.13程序中的display函数不放在Time类中,而作为类外的普通函数,然后分别在Time和Date类中将display声明为友元函数。在主函数中调用display函数,display函数分别引用Time和Date两个类的对象的私有数据,输出年、月、日和时、分、秒。请读者自己完成并上机调试。
#include
using namespace std;
class Date;
class Time
{public:
Time(int,int,int);
friend void display(const Date &,const Time &);
private:
int hour;
int minute;
int sec;
};
Time::Time(int h,int m,int s)
{hour=h;
minute=m;
sec=s;
}
class Date
{public:
Date(int,int,int);
friend void display(const Date &,const Time &);
private:
int month;
int day;
int year;
};
Date::Date(int m,int d,int y)
{month=m;
day=d;
year=y;
}
void display(const Date &d,const Time &t)
{
cout<
11. 将例9.13中的Time类声明为Date类的友元类,通过Time类中的display函数引用Date类对象的私有数据,输出年、月、日和时、分、秒。
#include
using namespace std;
class Time;
class Date
{public:
Date(int,int,int);
friend Time;
private:
int month;
int day;
int year;
};
Date::Date(int m,int d,int y):month(m),day(d),year(y){ }
class Time
{public:
Time(int,int,int);
void display(const Date &);
private:
int hour;
int minute;
int sec;
};
Time::Time(int h,int m,int s):hour(h),minute(m),sec(s){ }
void Time::display(const Date &d)
{
cout<
12. 将例9.14改写为在类模板外定义各成员函数。
#include
using namespace std;
template
class Compare
{public:
Compare(numtype a,numtype b);
numtype max();
numtype min();
private:
numtype x,y;
};
template
Compare::Compare(numtype a,numtype b)
{x=a;y=b;}
template
numtype Compare::max()
{return (x>y)?x:y;}
template
numtype Compare::min()
{return (x cmp1(3,7);
cout< cmp2(45.78,93.6);
cout< cmp3('a','A');
cout<