首页 > 编程语言 >南京邮电大学C++实验(一)类和对象的定义及使用(仅参考)

南京邮电大学C++实验(一)类和对象的定义及使用(仅参考)

时间:2024-03-16 14:32:39浏览次数:26  
标签:Boy 调用 定义 int 函数 邮电大学 C++ Girl 构造函数

实验名称:类和对象的定义及使用

一、实验目的和要求

(1)掌握类与对象的定义与使用方法,理解面向对象方法中通过对象间传递消息的工作机制。

(2)正确掌握类的不同属性成员的使用方法。

(3)掌握构造函数与析构函数的概念,理解构造函数与析构函数的执行过程。

(4)掌握友元函数和友元类的定义和使用。

(5)基本掌握指针和引用作为函数参数的应用。

二、实验环境(实验设备)

硬件:  微型计算机

软件:  Windows 操作系统、Microsoft Visual Studio 2010

三、实验原理及内容

实验题目1 定义一个借书证类BookCard,在该类定义中包括如下内容。

(1)私有数据成员:

string id;          //借书证学生的学号

string stuName;    //借书证学生的姓名

int number;       //所借书的数量

(2)公有成员函数:

构造函数       //用来初始化3 个数据成员,是否带默认参数值参考结果来分析

void display()   //显示借书证的3 个数据成员的信息

bool borrow()   //已借书数量不足10 则将数量加1,数量达到10 则直接返回false

主函数及f()函数代码如下。请结合输出结果完成程序。

void f(BookCard &bk)

{

        if (!bk.borrow())

        {

             bk.display();

             cout<<"you have borrowed 10 books,can not borrow any more!"<<endl;

        }

        else

             bk.display();

}

int main()

{

        BookCard bk1("B20190620","东平",10),bk2;

        f(bk1);

        f(bk2);

        return 0;

}

程序的运行结果为:

 B20190620 东平 10

 you have borrowed 10 books,can not borrow any more!

 B19010250 雪峰 4

参考实验教材中相应的实验指导,完成源程序代码如下:

//Test1—_h.h 定义BookCard类
#include<iostream>
#include<string.h>
using namespace std;
class BookCard
{
private:
    string id; //借书证的学生的学号
    string stuName;  //借书证学生的姓名
    int number;  //所借书的数量
public:
    BookCard(string a="B19010250", string b="雪峰", int c=4);
    //用来初始化3个数据成员,是否带默认参数值参考结果来分析
    void display();  //显示借书证的3 个数据成员的信息
    bool borrow(); //已借书数量不足10 则将数量加1,数量达到10 则直接返回false
};
//BookCard类成员函数
#include"1-1.h"
#include<iostream>
using namespace std;
BookCard::BookCard(string a, string b, int c) :id(a), stuName(b), number(c) 
//初始化列表初始化
{ }
void BookCard::display()
{
    cout << id << " " << stuName << " " << number << endl;
}
bool BookCard::borrow()
{
    if (number < 10)
    {
       number++;
       return true;
    }
    else
       return false;
}
//主程序
#include"Test1_h.h"
#include<iostream>
using namespace std;
void f(BookCard& bk)
{
    if (!bk.borrow())
    {
       bk.display();
       cout << "you have borrowed 10 books,can not borrow any more!" << endl;
    }
    else
       bk.display();
}
int main()
{
    BookCard bk1("B20190620", "东平", 10), bk2;
    f(bk1);
    f(bk2);
    return 0;
}

实验题目2 定义一个时间类Time,有三个私有成员变量Hour、Minute、Second,定义构造函数、析构函数以及用于改变、获取、输出时间信息的公有函数,主函数中定义时间对象,并通过调用各种成员函数完成时间的设定、改变、获取、输出等功能。

① 按要求完成类的定义与实现。

② 修改数据成员的访问方式,观察编译结果。

③ 在Time类中定义一个成员函数,用于实现时间增加一秒的功能,主函数中通过对象调用该函数,并输出增加一秒后的时间信息。

④ 定义一个普通函数。

void f(Time  t)

{  

         t. PrintTime( );

}

在Time类中增加拷贝构造函数的定义,主函数中调用该函数,运用调试工具跟踪,分析整个程序调用构造函数(包括拷贝构造函数)和析构函数的次数;再将f函数的形式参数分别修改为引用参数和指针参数(此时函数代码修改为{t-> PrintTime( );},主函数中调用,再分析此时调用构造函数和析构函数的次数。

参考实验教材中相应的实验指导完成程序,并回答相关问题。完成后的源程序代码如下:

#include<iostream>
using namespace std;
class Time
{
private:
    int Hour, Minute, Second;
public:
    Time(int h = 0, int m = 0, int s = 0);
    void Change(int h, int m, int s);
    int GetHour();
    int GetMinute();
    int GetSecond();
    void PrintTime();
    //void IncreaseOneSecond();
    ~Time();
};
Time::Time(int h, int m, int s)
{
    Hour = h;
    Minute = m;
    Second = s;
    cout << "Construct" << endl;
}
void Time::Change(int h, int m, int s)
{
    Hour = h;
    Minute = m;
    Second = s;
}
int Time::GetHour()//获取Hour
{
    return Hour;
}
int Time::GetMinute()//获取Minute
{
    return Minute;
}
int Time::GetSecond()//获取Second
{
    return Second;
}
void Time::PrintTime()
{
    cout << Hour << ":" << Minute << ":" << Second<< endl;
}
Time::~Time()
{
    cout << "Destructor:" << Hour << ":" << Minute << ":" << Second << endl;
}

int main()
{
    Time t1;
    Time t2(20);
    Time t3(20, 30);
    Time t4(20, 30, 56);
    t1.PrintTime();
    t2.PrintTime();
    t3.PrintTime();
    t4.PrintTime();
    t4.Change(23, 59, 59);
    t1.Change(14, 28, 12);
    cout << "ChangeTime" << t1.GetHour() << ":" << t1.GetMinute() << ":" << t1.GetSecond() << endl;
    cout << "ChangeTime" << t4.GetHour() << ":" << t4.GetMinute() << ":" << t4.GetSecond() << endl;

}

程序的运行结果是:

构造函数与析构函数的调用方式及执行顺序是:

调用方式:自动调用

执行顺序:先执行构造函数,程序结束时执行析构函数。
析构函数的调用顺序与构造函数相反。

③取消类中成员函数IncreaceOneSecond( )的注释标志,将该函数补充完整,注意时间在增加一秒情况下的进位关系。

该函数的代码如下:

void Time::IncreaseOneSecond()
{
    if (Second < 59)
       Second++;
    else
    {
       Second = 0;
       if (Minute < 59)
           Minute++;
       else
       {
           Minute = 0;
           if (Hour < 23)
              Hour++;
           else
              Hour = 0;
       }
    }
}

主函数中定义一个Time类对象并调用一次f函数,观察结果填写下表:

f函数的原型主函数中调用f的语句

构造函数

调用次数

拷贝构造函数

调用次数

析构函数调用次数
void f(Time t);f(t1);112
void f(Time &t);f(t1);101
void f(Time *t);f(&t1);101

通过以上结果,关于对象作形式参数、对象引用作形式参数、对象指针作形式参数时构造函数、析构函数的调用次数及顺序,你得到什么结论?

对象作为形式参数:

调用时,实参的值传给形参,要调用复制构造函数,且形参占内存空间,析构函数调用两次

对象引用作为形式参数:

相当于是实参的别名,就是对实参对象进行操作,形参不占内存空间,也不需要调用拷贝构造函数。

对象指针作形式参数:

不调用拷贝构造函数,通过指针可以访问实参对象的值,且未再次调用构造函数。

实验题目3 定义一个Girl类和一个Boy类,这两个类中都有表示姓名、年龄的私有成员变量,都要定义构造函数、析构函数、输出成员变量信息的公有成员函数。

①根据要求定义相应的类。

②将Girl类作为Boy类的友元类,在Girl类的成员函数VisitBoy(Boy & )中访问Boy类的私有成员,观察程序运行结果。

③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,观察编译器给出的错误信息,理解原因。

④主函数中正确定义两个类的对象,调用各自的成员函数实现相应功能。

⑤再将Boy类作为Girl类的友元类,在Boy类的某成员函数VisitGirl(Girl & )中访问Girl类的私有成员,观察编译器给出的信息。

⑥删除两个类中的函数VisitGirl(Girl & ) ,VisitBoy(Boy & ),定义一个顶层函数VisitBoyGirl(Boy &, Girl &),作为以上两个类的友元,通过调用该函数输出男孩和女孩的信息。

实验解答:

①定义相应的类,主函数中定义相应的类成员,调用各类的输出函数显示信息。

源程序代码如下:

#include<iostream>
#include<string>
using namespace std;
class Boy;
class Girl
{
private:
    string Name;
    int Age;
public:
    Girl(string N="ABC",int A=18 );
    void Output();
    //void VisitBoy(Boy&);
    ~Girl()
    {
       cout << "Girl destructing" << endl;
    }
};
class Boy
{
private:
    string Name;
    int Age;
    //friend Girl;
public:
    Boy(string N = "ABC", int A = 18);
    void Output();
    //void VisitGirl(Girl&);
    ~Boy()
    {
       cout << "Boy destructing" << endl;
    }
};
Girl::Girl(string N , int A )
{
    Name = N;
    Age = A;
    cout << "Girl constructing" << endl;
}
void Girl::Output()
{
    cout << "Girl's name:" << Name << endl;
    cout << "Girl's age:" << Age << endl;
}
Boy::Boy(string N , int A )
{
    Name = N;
    Age = A;
    cout << "Boy constructing" << endl;
}
void Boy::Output()
{
    cout << "Boy's name:" << Name << endl;
    cout << "Boy's age:" << Age << endl;
}
int main()
{
    Girl g("Lm", 19);
    Boy b("Zs", 20);
    g.Output();
    b.Output();
}

程序的运行结果是:

②将Girl类作为Boy类的友元类, 写出Girl类的成员函数VisitBoy(Boy & )的实现代码。

void Girl::VisitBoy(Boy& boy)
{
    cout << "Boy's name:" << boy.Name << endl;
    cout << "Boy's age:" << boy.Age << endl;
}

程序的运行结果是:

③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,记录编译器给出的错误信息,与②对比,你能得出友元的什么特性?

友元关系是单向的,不具有交换性

④在上面代码的基础上,在Girl类的定义中,增加一行代码:friend  Boy; 在主函数中通过Boy类对象. VisitGirl(Girl类对象) 的形式输出Girl类对象的信息。编译的结果是什么?写出这一步你的主函数代码,要求分别用友元函数Girl类对象. VisitBoy(Boy类对象);Boy类对象. VisitGirl(Girl类对象) ;和输出两个类对象的信息。

int main()
{
    Girl g("Lm", 19);
    Boy b("Zs", 20);
    g.VisitBoy(b);
    b.VisitGirl(g);
    b.Output();
    g.Output();
}

⑤定义一个顶层函数void VisitBoyGirl(Boy &, Girl &),作为以上两个类的友元函数,主函数中通过调用该函数输出男孩和女孩的信息。写出该友元函数的完整代码,以及主函数的代码。

void VisitBoyGirl(Boy& boy, Girl& girl)
{
    cout << "Boy's name:" << boy.Name << endl;
    cout << "Boy's age:" << boy.Age << endl;
    cout << "Girl's name:" << girl.Name << endl;
    cout << "Girl's age:" << girl.Age << endl;
}
int main()
{
    Girl g("Lm", 19);
    Boy b("Zs", 20);
    VisitBoyGirl(b, g);
}

四、实验小结(包括问题和解决方法、心得体会、意见与建议等)

(一)实验中遇到的主要问题及解决方法

1.在题目2中不改变main()函数中的对象的定义方式,若取消构造函数中参数的默认值,编译程序错误提示信息及出错原因是:

错误提示信息:

不能接受0个参数,没有重载函数接受两个参数

原因:

实际参数个数不能少于无默认值的形式参数个数

2.在题目2中如果删除类中自定义的构造函数,仅使用系统默认构造函数,再编译,程序错误提示信息及出错原因是:

错误提示信息:

没有与参数列表匹配的构造函数

原因:

系统默认的构造函数无形式参数

3.在题目2中如果将main()函数中的输出语句改为:cout<<对象名.Hour<<":"<<对象名.Minute<<":"<<对象名.Second<<endl; 重新编译,会出现什么错误提示?在这种情况下,如果将成员变量的访问属性修改为public再编译,结果如何?

错误提示信息:

Time::Hour无法访问private成员、Time::Minute无法访问private成员Time::Second无法访问private成员

结果:

成功运行

    4.其它问题及解决办法

问题:函数声明时指定默认参数后,函数首部再次指定

方法:删除函数首部的默认值,只保留形参

(二)实验心得

       通过本次实验,进一步熟悉了类的定义以及成员函数的使用,同时通过题目2和题目3对于publicprivate属性有了更深的体会。同时,掌握了关于构造函数和析构函数的调用方式和调用顺序的异同,以及不同形式对象做形式参数时,两者调用的情况和背后的原因。

(三)意见与建议(没有可省略)

标签:Boy,调用,定义,int,函数,邮电大学,C++,Girl,构造函数
From: https://blog.csdn.net/m0_72872046/article/details/136758796

相关文章

  • C++模板的显式实例化
    C++模板前面讲到的模板的实例化是在调用函数或者创建对象时由编译器自动完成的,不需要程序员引导,因此称为隐式实例化。相对应的,我们也可以通过代码明确地告诉编译器需要针对哪个类型进行实例化,这称为显式实例化。编译器在实例化的过程中需要知道模板的所有细节:对于函数模板,也就是......
  • 将C++模板应用于多文件编程
    C++模板在将函数应用于多文件编程时,我们通常是将函数定义放在源文件(.cpp文件)中,将函数声明放在头文件(.h文件)中,使用函数时引入(#include命令)对应的头文件即可。编译是针对单个源文件的,只要有函数声明,编译器就能知道函数调用是否正确;而将函数调用和函数定义对应起来的过程,可以延迟到......
  • 邻接表存储带权的无向图(c++题解)
    题目描述给出一个无向带权图,顶点数为n,边数为m。输入格式第一行两个整数n,m,接下来有m行,每行3个整数u,v,w,表示点u到点v有一条边,边权为w。输出格式第i行输出第点i的所有邻接点,按照点i到该点的边权由小到大输出,如果边权相等,则按照点的编号有小到大输出。样例样例输入复......
  • 有向图的DFS(c++题解)
    题目描述给定一个有向图(不一定连通),有N个顶点,M条边,顶点从1..N依次编号,求出字典序最小的深度优先搜索顺序。输入格式第1行:2个整数,N(1≤N≤200)和M(2≤M≤5000)接下来M行,每行2个整数I,J,描述一条边从顶点I指向顶点J输出格式仅一行,一个顶点编号序列,表示字典序最小的深度优先搜索......
  • C++模板的实例化
    C++模板模板并不是真正的函数或类,它仅仅是编译器用来生成函数或类的一张“图纸”。模板不会占用内存,最终生成的函数或者类才会占用内存。由模板生成函数或类的过程叫做模板的实例化,相应地,针对某个类型生成的特定版本的函数或类叫做模板的一个实例。在学习模板以前,如果想针对不同......
  • C++模板中的非类型参数
    C++模板模板是一种泛型技术,目的是将数据的类型参数化,以增强C++语言(强类型语言)的灵活性。C++对模板的支持非常自由,模板中除了可以包含类型参数,还可以包含非类型参数,例如:template<typename T, int N> class Demo{ };template<class T, int N> void func(T (&arr)......
  • C++示例:学习C++标准库,std::unordered_map无序关联容器的使用
    01std::unordered_map介绍std::unordered_map是C++标准库中的一种无序关联容器模板类,它提供了一种将键映射到值的方法。它的底层基于哈希表实现,内容是无序的,可以在平均情况下在O(1)的时间复杂度内完成插入、查找和删除操作。值得注意的是,哈希表可能存在冲突,即不同的键值......
  • 滴水逆向笔记系列-c++总结2-36.权限控制-37.虚函数-38.多态_绑定
    第三十六课c++3权限控制1.定义和实现分开写2.private和publicprivate权限说明私有变量在类外是无法访问的,只有在类内或者使用类内函数访问类内函数访问3.private真的不能访问吗反汇编看看t对象在初始化public和private成员时都是一视同仁的,在底层还是没区别,都是编......
  • 滴水逆向笔记系列-c++总结3-39.模板-40.引用_友元_运算符重载
    第三十八课c++6模板1.冒泡排序和折半查找voidSort(int*arr,intnLength) { inti; intk; for(i=0;i<nLength-1;i++) { for(k=0;k<nLength-1-i;k++) { if(arr[k]>arr[k+1]) { inttemp=arr[k]; a......
  • 滴水逆向笔记系列-c++总结4-41.new-delete-vector-42.链表
    第四十课c++8new-delete-vector1.内存空间复习在类外函数外的变量就是全局变量,程序一编译地址就已经确定了的临时数据,参数和局部变量就是在堆栈里而使用malloc函数动态申请的则是在堆里2.跟踪调试反汇编函数我们调用malloc函数申请内存,但是不是malloc一个函数完成整个......