经典案例总结:
1、接口的出现提高了功能的扩展型,接口作为一个特殊的抽象类。
实体里面定义的全部是抽象方法,只要想实现这个方法,就要在子类
中重写,而且必须实现全部方法的重写,如果只重写一部分,那么子类
也是一个抽象类。
2、多态的使用,提高了代码的程序的扩展性,我们只要使用接口的引用
指向子类的对象,就可以直接调用其中的方法了。
3、重写,子类方法对父类中的抽象方法进行了重写;
4、匿名对象,在这个程序中,匿名对象创建了对象,使接口引用有了指向,
而且匿名对象还作为实际参数进行传递。
class Test
{
public static void main(String []args)
{
MainBoard mb=new MainBoard();
mb.run();
mb.usePCI(new NetCard());//匿名对象
mb.usePCI(new SoundCard());
}
}
interface PCI//定义一个PCI接口,有两个抽象方法;
{
public abstract void open();
public abstract void close();
}
class MainBoard//主板自己要通电运行,同时还要使用PCI接口
{
public void run()
{
System.out.println("mainboard run");
}
public void usePCI(PCI p)//多态的体现PCI是个接口,接受实现它的各种对象
{
p.open();
p.close();
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("Netcard open"); }
public void close()
{
System.out.println("Netcard close"); }
}
class SoundCard implements PCI
{
public void open()
{
System.out.println("SoundCard open"); }
public void close()
{
System.out.println("SoundCard close"); }
}
一、简答题
1. 什么是类?什么是对象?对象与类的关系是什么?
答:类就是相同的数据和相同的一组对象的集合,即类是对具有相同数据结构和相同操作的一类对象的描述;
对象是描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体,对象可以认为是:数据+操作;
类和对象之间的关系是抽象和具体的关系。
2. 构造函数和析构函数的主要作用是什么?他们各有什么特性?
答:构造函数主要用于为对象分配空间,进行初始化。构造函数除了具有一般成员函数的特征外,还具有一些特殊的性质:
(1)构造函数的名字必须与类名相同
(2)构造函数可以有任意类型的参数,但不能指定返回类型。它有隐含的返回值,该值由系统内部使用。
(3)构造函数是特殊的成员函数,函数体可写在类体内,也可写在类体外。
(4)构造函数可以重载,即一个类中可以定义多个参数个数或参数类型不同的构造函数。
(5)构造函数被声明为公有函数,但它不能像其他成员函数那样被显式地调用,它是在定义对象的同时被调用的。
析构函数也是一种特殊的成员函数。它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。析构函数有以下一些特点:
(1)析构函数与构造函数名字相同,但它前面必须加一个波浪号(~);
(2)析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数;
(3)当撤消对象时,编译系统会自动地调用析构函数。
3. 有哪几种继承方式?每种方式的派生类对基类成员的继承性如何?
基类(父类)得私有成员,派生类(子类)都不能访问;
基类得公有成员,派生类得继承方式决定了其函数得形式!
基类得保护成员在派生类得公有继承中也是保护类型!
4. 简要叙述友元运算符函数和成员运算符函数有什么不同点? 答:三种继承方式(公有public、保护protected、私有private);继承性可参见教材P143。
答:(1)对双目运算符而言,成员运算符函数带有一个参数,而友元运算符函数带有两个参数;对单目运算符而言,成员运算符函数不带参数,而友元运算符函数带一个参数。
(2)双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但某些情况,必须使用友元函数。
5. 派生类构造函数和析构函数的执行顺序是怎样的?
答:当创建对象时,编译系统会自动调用构造函数。当撤销对象时,编译系统会自动调用析构函数。
当创建派生类的对象时,首先执行基类的构造函数,然后执行派生类的构造函数。
当撤销对象时,则先执行派生类的析构函数,然后再执行基类的析构函数。
6. 什么是虚函数?虚函数与函数重载有哪些相同点和不同点?
答:虚函数是一个在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数。声明虚函数的格式如下:
virtual <返回值类型> <函数名>(<参数表>);
在派生类中重新定义基类的虚函数是函数重载另一种形式,但它不同于一般的函数重载。
当普通的函数重载时,其函数的参数或参数类型必须有所不同,函数的返回类型也可以不同。 对于虚函数,如果仅仅是返回类型不同,其余均相同,系统会给错误信息;若仅仅函数名相同,而参数的个数、类型或顺序不同,系统将它作为普通的函数重载,这时虚函数的特性将丢失。
7. 函数重载
答:函数重载是指具有相似功能的不同函数使用同一函数名,但这些同名函数的参数类型、参数个数、返回值、函数功能可以不同。编译系统将根据函数参数的类型和个数来判断使用哪一个函数。体现了C++对多态性的支持。
8. 函数模板
答:可以把逻辑功能相同而函数参数和返回值类型不同的多个重载函数用一个函数来描述。参数化的函数称为函数模板,代表的是一个函数家族。定义:
template <模板参数表>
<返回值类型> <函数名>(<参数表>)
{
<函数体>
}
9. 类的继承和派生
答:类的继承就是根据一个类创建一个新类的过程。
类的派生就是从已有类产生新类的过程。
10. 多态性及其实现
答:多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。
多态的实现:
a)
b)
c) 函数重载 运算符重载 虚函数赋值兼容规则
11. 赋值兼容规则
答:一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:
a)
b)
c) 派生类的对象可以被赋值给基类对象。 派生类的对象可以初始化基类的引用。 指向基类的指针也可以指向派生类
12. 联编:静态联编,动态联编
答:联编又称绑定:是指计算机程序自身彼此关联的过程,也就是把一个函数名和一个函数体联系在一起的过程
静态联编:在编译过程中,编译系统可以根据类型匹配等特征来确定程序中调用操作与执行某个同名函数实现之间的关系,即确定某一个同名函数到底是要调用哪一段函数实现代码。
函数重载和运算符重载就是通过静态联编方式实现的编译时的多态的体现。
静态联编的优点是函数调用速度快、效率较高,缺点是编程不够灵活
动态联编:只有在运行程序时才能确定将要调用的函数。这种在运行阶段进行的联编称为动态联编。
动态联编的优点是提供了更好的编程灵活性、问题抽象性和程序易维护性,缺点是与静
态联编相比,函数调用速度慢
13. 纯虚函数和抽象类
答:带有纯虚函数的类称为抽象类:
抽象类的主要作用是将有关的派生类组织在一个继承层次结构中,由抽象类为它们提供一个公共的根,相关的派生类就从这个根派生出来。定义:
class 类名
{
virtual 类型 函数名(参数表)=0;
}
二、编程题
例1、 示例运算符重载,并与用成员函数实现的方式进行比较。计算应付给的人民币。 #include <iostream.h>
class RMB //人民币类
{
public:
};
RMB RMB::interest(double rate)
{
return RMB((yuan+jf/100.0)*rate);
}
RMB RMB::add(RMB d)
{
return RMB (yuan+d.yuan+jf/100.0+d.jf/100.0);
}
//以下是计算应付人民币的两种方法
RMB expense1(RMB principle,double rate)
//采用普通成员函数求本利和
{
RMB interests=principle.interest(rate);
return principle.add(interests);
} RMB(double d) { } RMB interest(double rate); //计算利息 RMB add(RMB d); //人民币相加 void display( ) { } { } RMB operator*(double rate) { } unsigned int yuan; //元 return RMB((yuan+jf/100.0)*rate); //运算符“*”重载函数 return RMB(yuan+d.yuan+ (jf+d.jf)/100.0); cout<<(yuan+jf/100.0)<<endl; yuan=(int)d; jf = (int)((d-yuan)*100); RMB operator+(RMB d) //运算符“+”重载函数 private: unsigned int jf; //角分
RMB expense2(RMB principle,double rate)
//采用运算符重载函数求本利和
{
RMB interests=principle*rate;
return principle+interests;
}
void main( )
{
RMB x=10000.0;
double yrate=0.035;
expense1(x,yrate).display();
expense2(x,yrate).display();
}
运行结果:
10350
10350
例2、 示例运算符重载为成员函数形式。复数类加法、减法和赋值运算符重载。 #include <iostream.h>
class Complex
{
public:
Complex(double r=0.0,double i=0.0){m_fReal=r;m_fImag=i;} //构造函数 double Real(){return m_fReal;} double Imag(){return m_fImag;} Complex operator + (Complex &c); Complex operator + (double d); Complex operator = (Complex x);
//返回复数的实部 //返回复数的虚部 //复数加复数 //复数加实数 //复数对象=复数 //私有数据成员 //复数类 //本金乘利率 //本利和 Complex operator - (Complex &c); //复数减复数 private: double m_fReal,m_fImag;
};
Complex Complex::operator+(Complex &c) //重载运算符“+”,两个复数相加 {
}
Complex Complex::operator +(double d)
{
Complex temp; temp.m_fReal=m_fReal+d; temp.m_fImag=m_fImag; return temp; //重载运算符“+”,一个复数加一个实数 Complex temp; temp.m_fReal=m_fReal+c.m_fReal; //实部相加 temp.m_fImag=m_fImag+c.m_fImag; //虚部相加 return temp;
}
Complex Complex::operator-(Complex &c) //重载运算符“-”,两个复数相减 {
}
Complex Complex::operator=(Complex c) //重载运算符“=”
{
}
void main()
{
}
例3、 示例单目运算符“++”重载为成员函数形式。
//example58.cpp
#include <iostream.h>
class Clock //时钟类
{
public:
Clock(int NewH=0,int NewM=0,int NewS=0);
void ShowTime();
void operator++();
private:
int Hour,Minute,Second;
};
Clock::Clock(int NewH,int NewM,int NewS) //构造函数
{
if(0<=NewH&&NewH<24&&0<=NewM&&NewM<60&&
0<=NewS&&NewS<60)
{ //前缀单目运算符重载函数的声明 //后缀单目运算符重载函数,加int参数以示区分 void operator++(int); Complex c1(3,4),c2(5,6),c3,c4; //定义复数类的对象 cout<<"c1="<<c1.Real()<<"+j"<<c1.Imag()<<endl; cout<<"c2="<<c2.Real()<<"+j"<<c2.Imag()<<endl; c3=c1+c2; c3=c3+6.5; //调用运算符“+”、“=”重载函数,完成复数加复数 //调用运算符“+”、“=”重载函数,完成复数加实数 cout<<"c3=c1+c2="<<c3.Real()<<"+j"<<c3.Imag()<<endl; cout<<"c3+6.5="<<c3.Real()<<"+j"<<c3.Imag()<<endl; c4=c2-c1; //调用运算符“-”、“=”重载函数,完成复数减复数 m_fReal=c.m_fReal; m_fImag=c.m_fImag; return* this; //*this表示当前对象 Complex temp; temp.m_fReal=m_fReal-c.m_fReal; return temp; //实部相减 temp.m_fImag=m_fImag-c.m_fImag; //虚部相减 cout<<"c4=c2-c1="<<c4.Real()<<"+j"<<c4.Imag()<<endl;
Hour=NewH;
Minute=NewM;
Second=NewS;
}
else
cout<<"Time error!"<<endl;
}
void Clock::ShowTime()
{
cout<<Hour<<":"<<Minute<<":"<<Second<<endl; }
void Clock::operator++( ) //前缀单目运算符重载函数的实现 {
Second++;
if(Second>=60)
{
Second=Second-60;
Minute++;
if(Minute>=60)
{
Minute=Minute-60;
Hour++;
Hour=Hour%24;
}
}
cout<<"++Clock:";
}
void Clock::operator++(int) //后缀单目运算符重载函数的实现 {
Second++;
if(Second>=60)
{
Second=Second-60;
Minute++;
if(Minute>=60)
{
Minute=Minute-60;
Hour++;
Hour=Hour%24;
}
}
cout<<"Clock++:";
}
void main() //显示时间函数的实现
{
Clock myClock(11,59,59);
cout<<"First time output:";
myClock.ShowTime();
myClock++;
myClock.ShowTime();
++myClock;
myClock.ShowTime();
}
运行结果:
First time output:11:59:59
Clock++:12:0:0
++Clock:12:0:1
例4、构建一个类book,其中含有两个私有数据成员qu和price,建立一个有5个元素的对象数组,将qu初始化为1~5,将price初始化为qu的10倍。显示每个对象的qu*price。 #include <iostream>
using namespace std;
class book
{
public:
void SetQu(double q)
{ qu=q;
}
void SetPrice(double p)
{ price=p;
}
void OutPut()
{ cout<<"Qu*Price="<<qu*price<<endl;
}
private:
double qu,price;
};
int main()
{
book b[5];
for(int i=0;i<5;i++)
{ b[i].SetQu(i+1);
b[i].SetPrice((i+1)*10);
}
for(int i=0;i<5;i++)
{ b[i].OutPut();
}
return 0;
}
例4、/*编写一个对具有n 个元素的数组x[]求最大值的程序,要求将求最大值的函数设计成函数模板。思路分析:数组元素类型为模版参数指定的*/
# include <iostream.h>
template <class T>
T fun(T x,T y)
{
return x>y?x:y;
}
#include "max.h"
void main()
{
int a[5]={4,9,56,120,5};
double b[5]={2.9,7.6,2.0,8.5,12.8};
int i=0;
int max1=a[0];
double max2=b[0];
for(i=0;i<5;i++)
{
max1=fun(max1,a[i]);
max2=fun(max2,b[i]);
}
cout<<"数组a最大值是:"<<max1<<endl;
cout<<"数组b最大值是:"<<max2<<endl;
}
例5、建立类普通的基类building,用来存储一座楼房的层数、房间数以及它的总平方米数。建立派生类house,继承building,并存储卧室与浴室的数量,另外,建立派生类office,继承building,并存储灭火器与电话的数目。创建一个office对象,设置相关属性(如:灭火器数量和电话数目等),并显示该属性。 class building{
private:
int nFloors,nRooms;
double nAreas;
public:
building(){}
building(int f):nFloors(f){}
building(int f,int r):nFloors(f),nRooms(r){}
building(int f,int r,double a):nFloors(f),nRooms(r),nAreas(a){}
void setFloors(int n){nFloors = n;}
void setRooms(int n){nRooms = n;}
void setAreas(double n){nAreas = n;}
int getFloors(){return nFloors;}
int getRooms(){return nRooms;}
double getAreas(){return nAreas;}
void display(){
cout<<"Floors:"<<nFloors<<"\nRooms:"<<nRooms<<"\nAreas"<<nAreas<<"\n";
} };
class house:public building{
private:
int nBedRooms,nBathRooms;
public:
house():nBedRooms(0),nBathRooms(0){}
house(int b):nBedRooms(b){}
house(int bed,int bath):nBedRooms(bed),nBathRooms(bath){}
void setBeds(int n){nBedRooms = n;}
void setBath(int n){nBathRooms = n;}
int getBeds(){return nBedRooms;}
int getBath(){return nBathRooms;}
void display(){
cout<<"BedRooms:"<<nBedRooms<<"\nBathRooms:"<<nBathRooms<<"\n"; }
};
class office:public building
{
public:
office():nApparatus(0),nTelephones(0){}
office(int app):nApparatus(app){}
office(int app,int tele):nApparatus(app),nTelephones(tele){}
void setApps(int n){nApparatus = n;}
void setTels(int n){nTelephones = n;}
int getApps(){return nApparatus;}
int getTels(){return nTelephones;}
void display(){
cout<<"Appatatus:"<<nApparatus<<"\nTelephones:"<<nTelephones<<"\n"; }
private:
int nApparatus,nTelephones;
};
void main(){
cylinder tempcy(3.5,2.0);
tempcy.vol();
office tempoff(10,8);
tempoff.display();
tempoff.setApps(20);
tempoff.setTels(30);
tempoff.display();
}
例3-9示例析构函数和重载构造函数
#include <iostream.h>
#include <string.h>
class Student
{public:
Student(); //无参数构造函数的声明
Student(char* pid,char* pname,int a,float s);//带参数构造函数的声明
//………中间函数省略
~Student(); //析构函数的声明
private:
char* id;char* name;
int age;float score;
};
Student::Student()
{
}
Student::Student(char* pid,char* pname,int a,float s)//带参数构造函数的实现
{
}
Student::~Student() //析构函数的实现
{
}
void main()
s2.display();
s2.chgId("03410101");
s2.chgName("Wang Min");
s2.chgAge(20);
s2.chgScore(85);
s2.display();
Student s3("03410101","Zhang Hua ",19,95); //调用带参数构造函数创建并初始化对象s3 s3.display();
} //主函数 { Student s2; //调用无参数构造函数创建对象s2 delete[] name; //释放用new申请的内存单元 delete[] id; //方括号表示将字符串所占用的空间全部释放掉 id=new char[strlen(pid)+1]; strcpy(id,pid); name=new char[strlen(pname)+1]; //动态申请内存单元 strcpy(name,pname); age=a; score=s; id=new char[9]; strcpy(id,"00000000"); name=new char[11]; strcpy(name," "); age=0; score=0; //无参数构造函数的实现
1.面向对象=对象+类+继承+通信2.对象是面向对象开发模式的基本成份。每个对象可用它本身的一组属性和它可以执行的一组操作来定义。…
Private私有化:一般的话只对外提供几个功能的话,会把具体实现的过程给封装起来,这样可可以不让外界随意改动代码,如果私有化成员…
面向对象总结下面只是我个人对面向对象的一点理解,希望大家多提意见。向对象有这么几个好处:可维护;可拓展;可复用。首先我们要知道一点…
1.子类与父类的关系?子类继承父类但不能继承private成员,子类只能有一个父类,如果省略了extends,子类的父亲就是obj…
构造函数就是类JS对象的组成scriptvararr=[1,2,3,4,5];vara=12;//变量:自由arr.a=5;//属…
安徽广播电视大学梁伍七一、引言中期评估之前,我校加强网络教学的同时,逐步形成了“面授辅导+网络教学+小组学习”的课程教学模式实践模…
《面向对象的程序设计基础》课程总结20xx~20xx学年第一学期基本结束,“面向对象的程序设计基础”课程的教学任务圆满完成。下面对…
本部分一共包括以下一些技术点:1.面向对象的概念2.什么是类,什么是对象,类和对象这间的关系3.什么是面向对象编程呢?4.如何抽象…
构造函数就是类JS对象的组成scriptvararr=[1,2,3,4,5];vara=12;//变量:自由arr.a=5;//属…
面向对象分析与设计课程总结成都东软学院计算机科学与技术系软件工程20xx级11310320xx3张波指导老师:Dr.夏磊面向对象的…