一、 明确的概念:
(1)理解类和对象的概念;(具体见附一)
类是抽象的 对象是具体的 例如:你、我、他 都是人 那么 你、我、他就是对象 人就是类
(2)掌握类与对象的定义方法;
类的定义:
class 类名{ … /*定义这个类*/}; 员名或成员函数 不能通过外部直接访问(不声明访问属性时 系统默认为私有) 当出现对象名.成员(私有)时 编译器报错
与private类似 但protected属性的成员可以继承 private不能继承
附:如何知道 该程序析构函数的调用顺序是p3 p2 p1 答:将拷贝构造函数中 改为x=2*; y=2* 析构函数中 在cout<<”Destructor is called.”之后添加<<”x=”< 构造函数不能由用户调用 即:对象名.构造函数名(参数)是错误的 构造函数是随着对象的声明而调用的 例如: class Student{Student(){cout<<”Hello.”< Coordinate p2(p1); Coordinate p3=p2; cout<<\"p3=(\"<<()<<\ 程序结束时 调用析构函数 注意析构函数 return 0; 的调用顺序 从上至下 依此为 p3 p2 p1的} 析构函数 (1) 记录程序的运行结果 (2) 将Coordinate类中带有两个参数的构造函数进行修改,在函数体内增加如下语句: cout<<”Constructor is called.”< Coordinate p4; ?错误原因:构造函数没有参数 构造函数为Coordinate::Coordinate(int ,int) Coordinate p5(2); ? 错误原因:参数数量不对 1. 根据注释语句的提示实现类Date的成员函数,并将完整的程序编译、连接成功以保证程序能够正确运行。 #include <> class Date{ public: void printDate(); 下面是一个计算器类的定义,请完成该类的成员函数的实现,并设计一个主函数使分析: 用该类和相关成员函数以测试 1.题目中 Date类的数据成员为day, month, year 且均该类设计的正确性。 为整型访问属性为私有 主函数中声明了testDay对象 #include class ClsName { public: int a,b; ClsName(int a,int b){cout<<\"Construct by two numbers.\"< int gety(){return y;} void setx(){cout<<\"Change X:\";cin>>x;} 重载:函数名相同,参数的类型不同或者个数不同、或者都不同。 即根据带入参数的类型、数量的不同,来实现不同的功能 void sety(){cout<<\"Change Y:\";cin>>y;} void print(){cout<<\"X=\"< int main() { int a,b; cout<<\"Test1:Input with 2 numbers, now please input two numbers:\"< cout<<\"\\nTest2:Input with a numbers, now please input a number:\"; cin>>a; ClsName t2(a); (); ();(); (); cout<<\"\\nTest3:Without numbers\"; ClsName t3; (); ();(); (); return 0; 5. 建立类cylinder,包括两个数据成员radius和height,分别表示圆柱体的半径和高度, cylinder类的构造函数被传递了两个double值来初始化这两个成员;定义成员函数area()和volume用来求圆柱体的表面积和体积,定义成员函数print()打印cylinder类的相关信息。最后,在主函数中对cylinder类的设计进行测试。 这题很简单 没啥说的 #include<> class cylinder { public: }; int main() { int a,b; cylinder v; cout<<\"Radius=\"; void set(double r,double h){radius=r,height=h;} double area(){return (radius*;} double volume(){return (height*area());} void print(){cout<<\"Area=\"<private: } cin>>a; cout<<\"Height=\"; cin>>b; (a,b); (); return 0; 6. 定义一个学生类CStudent实现简单的学籍管理功能,要求该类至少实现以下功能: (1) 录入学生的基本信息(包括姓名,学号,性别,年龄,专业,入学时间,各门功课成绩) (2) 输出学生的基本信息 (3) 选课(输入时间和所选的课程) (4) 统计每门课的学分绩点 (5) 统计每学期的平均学分绩点 (6) 统计重考科目 (7) 统计重修科目 #include string name,sex,ID,object,jtime;< 通过对角标的控制 便可以把一行数据全部对 cout<<\"Mark:\";cin>>mark[i]; 应起来 } } 请看下面数据对应关系: void baseprint() .相当于score=score+... 无法确定第一个score的值 角标 科目名称成绩学分 retry=0; (sbj[i]) (mark[i]) (m_mark[i]) for(i=0;i 1 ”C语言 92 if(mark[i]>=60)score+=m_mark[i]; 2010-3-23,否则会导致部分功能不正常 6 2 英语 72 4 (5)掌握静态数据成员和静态成员函数的使用方法; 便于统计也可以方便地调用出一门科目的 例如:有Object类,拥有数据成员a,由Object类声明出的对象A、B、C,那么A、B、C都拥有各自的a,全部内容 内存中也会分配出各自的内存空间A::a,B::a,C::a(共3个)。而如果将数据成员a声明为静态成员(static),那么A、B、C则共用一个内存空间a(只有1个) 最典型的例子是统计声明对象的数量 使用方法: static 数据类型 数据成员名 由于不能直接对数据成员赋初值 所以静态数据成员初始化方法为: 数据类型 类名::静态数据成员名=初值(注意:1.是类名,不是对象名;2.之前不要加static) 静态成员函数 静态成员函数属于整个类 而不是某个对象 所以调用方法为 类名::静态成员函数名(参数表) 其他参看书P103几点说明 练习项目 Time类的框架定义如下: #include<> 计一个用来表示直角坐标系的Location类,在主程序中创建类Location的两个对象A和B,要求A的坐标在第3象限,B的坐标点在第2象限,分别采用成员函数和友元函数计算给定两个坐标点之间的距离,要求按如下格式输出结果: A(x1, y1), B(x2, y2) Distance1=d1 Distance2=d2 其中:x1, x2, y1, y2为指定的坐标值,d1和d2为两个坐标点之间的距离。Location类框架可参考如下: #include<> #include Location::Location(double a,double b) { } double Location::Getx() { } double Location::Gety() { } double Location::distance1(Location &L) { return sqrt(*+*); return y; return x; x=a; y=b; double x,y; \";} } int main() { double a,b; cout<<\"输入A点坐标(在第二象限):\"< Location A(a,b); cout<<\"输入B点坐标(在第四象限):\"< cin>>a; if(a>0)break; cin>>b; if(b>0)break; cout<<\"不对,再来一次:\"; cin>>a; if(a<0)break; cout<<\"不对,再来一次:\"; } cout<<\"不对,再来一次:\"; } } Location B(a,b); cout<<\"A(\"<<()<<\ cout<<\"B(\"<<()<<\ cout<<\"Distance1=\"<<(B)< cin>>b; if(b<0)break; cout<<\"不对,再来一次:\"; 3. 使用C++的string类,将5个字符串按逆转后的顺序显示出来。例如,逆转前的5个字符串是: Germany Japan America Britain France 逆转后的顺序输出字符串是: France Britain America Japan Germany #include string str1,str2,str3,str4,str5; cin>>str1>>str2>>str3>>str4>>str5; cout< 设计一个模仿类magic来实现4*4的魔方阵。类的框架如下: #include class magic 31917725211915 13112327291351917257111315 1921232729313531917725211915 13112327291355. 声明一个Employee类,数据成员包括:一个long型的id,两个字符指针成员,代表职员的姓名和家庭住址,一个double数据,代表月薪。成员函数有:构造函数、析构函数、set_salary()和get_salary()代表修改和获取薪资、set_name()和get_name()代表修改和获取姓名、set_address()和get_address()代表修改和获取家庭住址,set_id()和get_id()用来修改获取当前职员的id号。在主程序中,创建对象数组调用上述函数以测试Employee类设计的正确性。Employee类的框架可参考: #include et_id(a); p=new char[1000]; cout<<\"员工姓名:\";cin>>p; s[j].set_name(p); p=new char[1000]; cout<<\"员工住址:\";cin>>p; s[j].set_address(p); } } for(j=0;js[j].print(); return 0; cout<<\"输入员工工资:\"; cin>>b; s[j].set_salary(b); 6. 声明一个Student类,在该类中包括一个数据成员:score(代表课程成绩)、两个静态数据成员:total_score(代表总分),count(代表学生总人数)。成员函数有:构造函数、析构函数、account(int)用于设置分数、静态成员函数sum()返回所有学生的总成绩、静态成员函数average()返回所有学生的平均成绩、print()用于打印当前学生对象的成绩等。在主程序中,输入某班同学的成绩,并调用上述函数打印全班同学的成绩、求出全班学生的成绩之和与平均分等。Student类的框架可参考: #include class Student ccount(a); } cout<<\"输出全班int j=1; while(i>0) { } s[0].print2(); return 0;} s[--i].print(); if(j++%6==0)cout< 非静态成员的初始化方式的区别。 实验三 派生与继承 (2010-3-23) 二、 实验名称: 派生与继承。 三、 实验目的: (1) 理解继承的含义,掌握派生类的定义方法和实现; 继承就是子承父类 看书注意格式 私有成员不能继承 父类的保护成员继承成变为子类的私有成员 (2) 理解公有继承下基类成员对派生类成员和派生类对象的可见性,能正确地访问继承层次中的各种类成 员; (3) 理解保护成员在继承中的作用,能够在适当的时候选择使用保护成员以便派生类成员可以访问基类的 部分非公开的成员; (4) 理解虚函数在类的继承层次中的作用,虚函数的引入对程序运行时的影响,能够对使用虚函数的简单 程序写出程序结果。 四、 练习项目 1.先定义“点”类Point,再由“点”类派生出“圆”类Circle。 #include <> #define PI class Point 多重继承中基类构造函数和析构函数的调用顺序 #include <> class Base1 { protected: int data1; public: Base1(int a=0) { data1 = a; cout<<\"Base Constructor1\\n\"; } ~Base1( ) { cout<<\"Base Destructor1\\n\"; } }; class Base2 { protected: int data2; public: Base2(int a=0) { data2 = a; cout<<\"Base Constructor2\\n\"; } ~Base2( ) 运行结果: Base Constructor1 Base Constructor2 Derived Constructor 1,2,3 Derived Destructor Base Destructor2 Base Destructor1 Press any key to continue 要求记住调用顺序 4.对象成员构造函数和析构函数的调用顺序 #include <> class Base1 { protected: int data1; public: Base1(int a=8) { cout<<\"Base Destructor2\\n\"; } }; class Derived: public Base1, public Base2 { int d; public: Derived(int x, int y, int z):Base1(x), Base2(y) { d=z; cout<<\"Derived Constructor\\n\"; } ~Derived( ) { cout<<\"Derived Destructor\\n\"; } void Show( ) { cout< void main( ) { Derived c(1, 2, 3); ( ); } (1) 记录程序的运行结果 { data1 = a; cout< { cout< class Base2 { protected: int data2; Base1 b1, b2; public: Derived(int x, int y, int z) : Base1(x), Base2(y), b1(x+y), b2(x+z) }; void main( ) { Derived c(1, 2, 3); { d=z; cout<<\"Derived Constructor\\n\"; } ~Derived( ) { cout<<\"Derived Destructor\\n\"; } void Show( ) { cout< Base2(int a=9) { data2 = a; } ~Base2( ) { cout< (1) 记录程序的运行结果 1, Base Constructor1 2, Base Constructor2 3, Base Constructor1 4, Base Constructor1 Derived Constructor 1,2,3 Derived Destructor 4, Base Destructor1 3, Base Destructor1 2, Base Destructor2 1, Base Destructor1 Press any key to continue 5. 编程题 假设某商店有如下几种货品:衬衣、帽子、立柜。每一种货物都有与其关联的说明信息。 衬衣:单价、产地、库存量、布料; 帽子:单价、产地、库存量、布料、样式(平顶或尖顶); 立柜:单价、产地、库存量、木料、颜色。 对这些商品的操作有:商品的进库(增加库存量),商品的出库(减少库存量),该类货 品总价格的计算。 要求自行设计数据结构,用类的继承与派生关系将上述的各种货品表示出来,并使用类 的构造函数来初始化每一类对象的初始数据。而后将上述的商品管理计算机化,完成操作要 求的功能。 【实现方法提示】 1.设立3 个不同的类来描述与处理3 种不同的货品。首先注意到上述3 种货品数据之 } 间的相互关联关系,可使用C++基类及其派生类的定义方法,先抽象出(“提取”出)如下每 一货品都具有的 “公有”数据构成一个所谓的基类base,而后再派生出所需的那3 个类。 (1)base(基)类:单价、产地、库存量; (2)由base 作为基类,派生出shirt(衬衣)类:增加“布料”数据; (3)由base 出发,派生出wardrobe(立柜)类:增加“木料”与“颜色”数据; (4)而后又由shirt 类出发(作为基类),派生出cap(帽子)类:增加“样式”数据。 2.对应于要对各类数据所进行的操作,而设立出类的如下几个成员函数。 (1)构造函数 通过传递来的实参数据,来构造出每一对象所具有的各数据成员。如基类base 需要传 递place、count 与price 三项数据,而派生类shirt 则需在base 数据的基础上增加第四项 即布料数据material 等。 (2)商品的进库(增加库存量) void in_something(int add_cnt); 将对象的库存量count 增加一个数量add_cnt。 (3)商品的出库(减少库存量) void out_something(int del_cnt); 将对象的库存量count 减少一个数量del_cnt。 (4)该类货品总价格的计算 double total_price(); 通过使用“price*count”计算并返回对象所代表货品的总价格。 (5)对象数据的输出。 在屏幕上显示出对象所拥有的当前数据。 代码: #include string place; int count; double price; public: base(string pl,double pr,int c); void in_something(int add_cnt); void out_something(int del_cnt); }; class wardrobe:public base{ string color; string wood; public: wardrobe(string pl,double pr,int c,string co,string wo):base(pl,pr,c) { color=co; wood=wo; } void print(); }; class shirt:public base{ protected: string material; public: shirt(string pl,double pr,int c,string ma):base(pl,pr,c) { material=ma; } void print(); }; class cap:public shirt{ string style; public: cap(string pl,double pr,int c,string ma,string st):shirt(pl,pr,c,ma) { style=st; } void print(); }; base::base(string pl,double pr,int c) { place=pl; price=pr; count=c;} void base::in_something(int add_cnt) { count+=add_cnt; } void base::out_something(int del_cnt) { count-=del_cnt; if(count<0)count=0; } void shirt::print() { cout<<\"衬衣\产地:\"< shirt s(\"广州\棉\"); cap c(\"苏州\帆布\ wardrobe w(\"福建\红色\樟木\"); string a; cout<<\"有如下商品:\"< } while(a!=\"0\") { cout<<\"输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0)\"< cout<<\"+为入库 -为出库 为查询\";cin>>a; if(a==\"+\"){cout<<\"入库数量:\";cin>>temp;(temp);} if(a==\"-\"){cout<<\"出库数量:\";cin>>temp;(temp);} if(a==\"\")(); } else if(a==\"c\"){ cout<<\"+为入库 -为出库 为查询\";cin>>a; if(a==\"+\"){cout<<\"入库数量:\";cin>>temp;(temp);} if(a==\"-\"){cout<<\"出库数量:\";cin>>temp;(temp);} if(a==\"\")(); } else if(a==\"w\"){ cout<<\"+为入库 -为出库 为查询\";cin>>a; if(a==\"+\"){cout<<\"入库数量:\";cin>>temp;(temp);} if(a==\"-\"){cout<<\"出库数量:\";cin>>temp;(temp);} if(a==\"\")(); } else if(a==\"0\"){();();();} else cout<<\"有误 重新\"; } return 0; 运行结果: 有如下商品: 衬衣 产地:广州 布料:棉 单价: 数量:20 总价:1116 帽子 产地:苏州 布料:帆布 样式:A 单价: 数量:30 总价:705 立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000 输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) s +为入库 -为出库 为查询+ 入库数量:20 输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) c +为入库 -为出库 为查询- 出库数量:100 输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) w +为入库 -为出库 为查询 立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000 输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) 0 衬衣 产地:广州 布料:棉 单价: 数量:40 总价:2232 帽子 产地:苏州 布料:帆布 样式:A 单价: 数量:0 总价:0 立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000 Press any key to continue 实验四 (2010-4-23) 多态程序设计 实验目的: (1)掌握运算符重载的方法; 运算符其实相当于一个函数 只不过我们平时使用的是它的隐式形式 重载是函数名不变,带入函数的参数个数不变,但参数类型必须改变,返回值类型改变,功能也随之发生相应变化 其实质是将函数功能拓展 函数重载的方法与定义一个函数的方法几乎完全相同 格式为: 返回值类型 作用域::重载函数名 (参数表){函数定义} 注意:类其实也可以看做是一种数据类型 所以return 之后可以返回一个对象 (2)掌握使用虚函数实现动态多态性; 也叫动态联编 是通过指针实现的 练习项目 1.定义Point类,有坐标x,y两个成员变量,利用友元函数对Point类重载“++”运算符,实现对坐标值的改变。具体要求如下: (1) 编写程序定义Point类,在类中定义整型的私有成员变量x,y; (2) 在类中定义两个友元函数,分别重载前置++和后置++; (3) 编写主函数测试。 注意函数有无返回值的区别,以及返回值是否带有&应用符号。 1程序代码: #include<> 义Point类,有坐标x,y两个成员变量,利用运算符重载对Point类重载“++”运算符,实现对坐标值的改变。具体要求如下: 1) 编写程序定义Point类,在类中定义整型的私有成员变量x,y; 2) 定义成员函数Point& operator++(); Point operator++(int);以实现对Point类重载“++”运算符,分别重 载前置++和后置++; 3) 编写主函数测试。 2 程序代码: #include 义一个分数类,通过重载运算符实现分数的四则运算、求负运算和赋值运算。其中,要求加法“+” 和减法“-”用友元函数实现重载,其他运算符用成员函数实现重载。 3程序代码: #include<> #include<> 义一个车(vehicle)基类,有Run、Stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类, 从bicycle和motorcar派生出摩托车(motorcycle)类,它们都有Run、Stop等成员函数。具体要求如下: (1) 编写程序定义一个车(vehicle)基类,有Run、Stop等成员函数; (2) 由车(vehicle)基类派生出自行车(bicycle)类、汽车类(motorcar),从bicycle类和motorcar类派 生出摩托车类(motorcycle),它们都有Run、Stop等成员函数。 (3) 在main()函数中定义vehicle、bicycle、motorcar、motorcycle的对象,调用其Run()、Stop()函数, 观察其执行情况。 (4) 分别用vehicle类型的指针来调用几个对象的成员函数,看看能否成功(提示:把Run、Stop定义为 虚函数)。 4程序代码: #include using namespace std; 写程序,定义抽象基类Container,由此派生出2个派生类球体类Sphere,圆柱体类Cylinder,分别用虚函数分别计算表面积和体积。 (1) 球体的表面积为:4r2,球体的体积为 4r3; 圆柱表面积为: 2πR(h+R) 圆柱3体的体积πR2h。 (2) 定义相应的对象,编写主函数测试。 5程序代码: #include 计一个时钟类TIME,内含数据成员hour,minute,second表示时间,成员函数set( )设置时间数据,show( )显示时间数据。重载运算符 ++和-- (具有返回值),每执行一次++,second自增1,执行一次--,second自减1。second和minute的值在0~59区间循环(满59后再自增则归0,minute加1;second为0时再自减则为59,minute减1)。hour的值在0~23区间循环。 else if(a==\"reset\")(); 6程序代码: else if(a==\"0\")break; #include Now Input:time-- Run second-- Now time:00:00:00 Now Input:--time Run --second Now time:23:59:59 Now Input:0 Press any key to continue 附一:简介类和对象(个人理解) 类是抽象的 对象是具体的 知道这些可能还不理解 那就再具体一点吧 假设我们身边有A、B、C三个同学 A同学 在101宿舍6号床上铺 有1张床 2个杯子 1条毛巾 4件衣服 B同学 在102宿舍5号床下铺 有1张床 1个杯子 2条毛巾 3件衣服 C同学 在202宿舍1号床下铺 有1张床 3个杯子 2条毛巾 2件衣服 有上可以总结出 住所(字符串型) 床(整型) 杯子(整型) 毛巾(整型) 衣服(整型) 那么同学就是 一个类 其中包含了数据成员 住所、床、杯子、毛巾、衣服 A、B、C三名同学就是 同学类的对象 其实我们可以把类看做是一种数据类型 例如:Student类 中声明出了 A对象 int型 中声明出了a变量 Student A; int a; 类是由各种成员构成的 其中包括数据成员 和 成员函数 数据成员用来存放类内的所有数据 成员函数是用来体现类的功能的 一个没有成员函数的类是空洞的 因为它不具备除了存取之外的任何功能(包括计算 输入输出 等等) 注意类中成员和访问属性(私有、公有、保护)是两个概念 即:不一定数据成员必须就是私有的,成员函数是公有的 成员函数可以是私有的 数据成员也可以是公有的 这只是为了涉及数据保护而进行的编程习惯的培养 因为 “主体?函数?数据” 比 “主体?数据” 更具有安全性 (因为函数部分可设置保密功能) 具体一点 Function1(…)子函数1 int main(void)主函数 各种功能 内存区(形参) 各种功能 访 复制 问内存区(实参) Function2(…)子函数2 各种功能 复制 内存区(形参) 这是不涉及对象的 通过主函数和子函数实现功能 的机制演示 主函数与子函数的内存完全独立 互不影响 但是子函数无法直接调用实参(指针除外) int main(void)主函数 各种功能 对象B 公有成员函数(功能区) 公有数据成员(内存区) 访 问 访 属 问 性属 ? 性 私有/保护数据成员(内 存区) 私有/保护成员函数 与子函数不同 对象的内存区就在主函数中 是否能够调用由访问属性决定 对象A 公有成员函数 公有数据成员 附二: 设置函数与读取函数的作用机制(以实验一 第二题为例) 对象 首先要明确:赋值、读取、调用都是对成员的访问 由于访问属性将数据成员设置为私有所以 主函数 设置值 数据成员 主函数直接向对象中的私有数据成员赋值 成员函数(设置值) 是不允许的 值传递 由于设置函数是公有的 可以由主函数直接调用 那么就可以将要输入的值作为形参传如设置函数 再通过这个形参来最终修改成员函数的值 同样的,私有成员不能读取 那么也只能通过设立读取函数来返回数据成员的内容 对象 数据成员 主函数 成员函数(读取值) 附三 部分编程习惯 私有/保护数据成员 私有/保护成员函数 1.编程时建议使用“Tab”制表符来进行缩进 体现逻辑性 2.使用if语句和for语句时一定用{}表明逻辑性,并且大括号独占一行 例如: for(i=0;i 3.运行结果出现溢出或烫 则表明程序输出了无法预料的内容 (只开辟了内存空间而并未赋值的内容都是无法预料的) 烫的应对方法: 输出函数都是以’\\0’为截止标志的,不正确的复制字符串数组容易将’\\0’的复制忽略掉,从而输出了无法预料的内容,所以复制时要检查最后一位(a[i+1])是否是’\\0’若不是则要添加上。而且尽量使用strcpy(a,b)函数来复制字符串数组 数据溢出的应对方法: 确认构造函数或设置函数的赋值方式是否是 “实参=形参”,若为“形参=实参”那必定出错 使用形如i+=j 或i*=j时,要确定i有初值(加法通常将i初值设为0,乘法设为1) 运算时,数据类型要尽量匹配,有时类型转换不当也容易造成溢出 4.边编写边编译 每写完一个函数时,建议至少编译一次以确保正确性,也防止问题的积累,任何人都不能做到编译一次通过 一定要多练昂~~ 一定要看懂 看透每一道练习题 多练才能记住程序的各种烦人的格式 看懂才能独立做出一道题,遇到问题才能顺利解决 好嘞 祝大伙期末考个好成绩昂 因篇幅问题不能全部显示,请点此查看更多更全内容