《C++面向对象程序设计》教案由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“c语言程序与设计教案”。
《面向对象程序设计》课程教案
课程编号:08051230
课程名称:面向对象程序设计(Object-oriented Programming)学时:72学时,其中理论学时54,上机学时18 学分:3.5开课部门:数学与计算机科学学院 开课教研室:计算机科学 开课教师:雷小园 开课学期:第7学期
授课班级:04信计
先修课程:C语言程序设计
考核要求:考试,平时10%,实验20%,考试70% 使用教材:
《C++面向对象程序设计教程(第2版)》,陈维兴,清华大学出版社,2004年 《C++面向对象程序设计习题解答与实验指导》,陈维兴,清华大学出版社,2004年
教学目的与要求:
《面向对象程序设计》是一门计算机及相关专业的重要的专业基础课。本课程讲述C++语言面向对象的基本特性,包括类、对象、派生类、继承、运算符重载、多态性、虚函数、函数模板、类模板、输入输出、流类库、文件等,使学生掌握面向对象程序设计的基本概念和基本方法,能运用C++语言进行基本的面向对象程序设计。
教学方法:
采用板书讲解C++程序设计,再加以上机练习C++编程。
3章 类和对象
3.1 类与对象的基本概念
3.2 构造函数与析构函数
例:点类 Point cla Point { private: int x,y;public: Point(){};Point(int xx, int yy){ x=xx;y=yy;} Point(Point &p){ x=p.x;y=p.y;} int GetX()const { return x;} int GetY()const { return y;} void SetXY(int xx, int yy){ x=xx;y=yy;} void Show();};void Point::Show(){ cout
例:人类 Person cla Person { protected: char *name;int age;char sex;public: Person(char *n, int a, char s);Person(){ name = 0;age = 0;sex = ' ';} Person(Person &p);~Person(){ delete[] name;} void SetName(char *n);void SetAge(int a){ age = a;} void SetSex(int s){ sex = s;} char *GetName()const { return name;} int GetAge()const { return age;} char GetSex()const { return sex;} void Show();};
#include “person.h” #include using namespace std;
Person::Person(char *n, int a, char s){ name = new char[strlen(n)+1];strcpy(name,n);age = a;sex = s;} Person::Person(Person &p){ name = new char[strlen(p.name)+1];strcpy(name,p.name);age = p.age;sex = p.sex;} void Person::SetName(char *n){ delete[] name;name = new char[strlen(n)+1];strcpy(name,n);} void Person::Show(){ cout
1、对象数组
所谓对象数组是指每一数组元素都是对象的数组。
2、对象指针
声明对象指针的一般语法形式为:类名* 对象指针名。当用指向对象的指针来访问对象成员时,要用“->”操作符。
3、this指针
C++为成员函数提供了一个名字为this的指针,这个指针称为自引用指针。每当通过一个对象调用一个成员函数时,系统就自动把这个this指针指向该对象。因此使用的数据成员就是该对象的数据成员。
3.4 向函数传递对象
1、使用对象作为函数参数
2、使用对象指针作为函数参数
3、使用对象引用作为函数参数
3.5 静态成员
1、静态数据成员
在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。与一般的数据成员不同,无论建立多少个类的对象,都只有一个静态数据的拷贝。从而实现了同一个类的不同对象之间的数据共享。
定义静态数据成员的格式如下: static 数据类型 数据成员名;静态数据成员在该类定义之外被初始化。访问静态数据成员可以通过对象或指针来访问,也可以通过类名::来访问。
2、静态成员函数
定义静态成员函数的格式如下: static 返回类型 静态成员函数名(参数表);与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种: 类名::静态成员函数名(实参表)对象.静态成员函数名(实参表)对象指针->静态成员函数名(实参表)
例:点类 Point(演示静态成员)cla Point { private: int x,y;static int count;public: Point(int xx=0, int yy=0){ x=xx;y=yy;count++;} Point(Point &p){ x=p.x;y=p.y;count++;} int GetX()const { return x;} int GetY()const { return y;} void SetXY(int xx, int yy){ x=xx;y=yy;} static int GetCount(){ return count;} };
int Point::count=0;
int main(){ Point a(100,200), b;cout
3.6 友元
1、友元函数
友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有成员、保护成员和公有成员。
2、友元成员
一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的所有成员,还可以访问friend声明语句所在类对象中的所有成员。
3、友元类
一个类也可以作为另一个类的友元。
友元关系是单向的,不具有交换性。若类X是类Y的友元,类Y不一定是类X的友元。友元关系也不具有传递性。若类X是类Y的友元,Y是类Z的友元,类X不一定是类Z的友元。
例:点类 Point(演示友元)cla Point { private: int x,y;static int count;public: Point(int xx=0, int yy=0){ x=xx;y=yy;} int GetX()const { return x;} int GetY()const { return y;} void SetXY(int xx, int yy){ x=xx;y=yy;} friend double Dist(Point p1, Point p2);};
friend double Dist(Point p1, Point p2);{ double x,y;x=p1.x-p2.x;y=p1.y-p2.y;return sqrt(x*x+y*y);}
int main(){ Point a(100,200), b(300,400);cout
例:圆类 Circle(包含Point类的写法)cla Circle { private: double radius;//半径 Point center;//圆心 public: Circle(){} Circle(int x, int y, double r): center(x,y){ SetRadius(r);} Circle(Point p, double r): center(p){ SetRadius(r);} double GetRadius()const { return radius;} void SetRadius(double r){ radius =(r>=0 ? r : 0);} void SetValue(int x, int y, double r){ center.SetXY(x,y);SetRadius(r);} double Area();void Show();};
const double PI=3.14159;inline double Circle::Area(){ return PI * radius * radius;}
void Circle::Show(){ cout
1、const引用
const引用的说明形式如下: const 类型说明符& 引用名
2、const对象
const对象的说明形式如下: const 类名 对象名[(参数表)];如:const Data Mybirthday(1980,1,1);const对象的数据成员值不能被改变,const对象必须进行初始化。通过const对象只能调用它的const成员函数,而不能调用普通成员函数。
3、const数据成员
const数据成员只能通过构造函数的初始化列表来获得初始值。
4、const成员函数
const成员函数的说明格式如下: 类型说明符 函数名(参数表)const;如:int GetYear()const { return year;} const成员函数不能更新对象的数据成员,也不能调用对象的普通成员函数。const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
5、引用类型的数据成员
引用类型的数据成员也只能通过构造函数的初始化列表来进行初始化。
例
cla Test { private: int a;const int b;//不能写成const int b=10,因类的定义还没分配空间 int &c;//不能写成const int &c=a,因变量a还没分配空间 public: Test(int i,int j,int &k):b(j),c(k){ a=i;} Test():b(10),c(a){ a=20;} } 第4章 派生类与继承
4.1 派生类的概念
4.2 派生类的构造函数与析构函数
例:圆类 Circle(继承Point类的写法)cla Circle: public Point { private: double radius;//半径 public: Circle(){} Circle(int x, int y, double r): Point(x,y){ SetRadius(r);} Circle(Point p, double r): Point(p){ SetRadius(r);} double GetRadius()const { return radius;} void SetRadius(double r){ radius =(r>=0 ? r : 0);} void SetValue(int x, int y, double r){ SetXY(x,y);SetRadius(r);} double Area();void Show();};
const double PI=3.14159;inline double Circle::Area(){ return PI * radius * radius;}
void Circle::Show(){ cout
1、派生类继承了它的所有基类中除构造函数和析构函数之外的所有成员。
2、在派生类中成员按访问属性划分为四种:不可访问的成员、私有成员、保护成员、公有成员。
3、对从基类继承下来的成员初始化工作是通过调用基类的构造函数来完成的,调用方法是在派生类的构造函数中用初始化列表。
4、如果在派生类的构造函数省略了基类的初始化列表,则将调用基类的缺省构造函数。
5、如果基类定义了带有参数的构造函数时,派生类就应当定义构造函数,以便显式地调用基类的构造函数。
6、如果派生类定义了与基类同名的新数据成员或成员函数,则此派生类的成员就覆盖了基类的同名成员,直接使用成员名只能访问到派生类的成员。
7、在同名覆盖的情况下,可以使用基类名+作用域分辨符来访问基类的同名成员。
8、如果派生类和基类的某个成员函数重名,但参数表不同,仍然属于覆盖,不属于重载。
9、对派生类的对象,构造函数的执行过程是:先调用基类的构造函数(按它们被继承时声明的顺序),再调用内嵌对象成员的构造函数(按内嵌对象声明的顺序),最后执行自己的构造函数体中的内容。
10、析构函数的调用次序正好和构造函数的调用次序相反。
例:学生类 Student //student.h #include “person.h” cla Student: public Person { protected: char *Department;int Number;public: Student(){ Department = 0;Number = 0;} Student(char *, int, char, char *, int);Student(Student &stu);~Student(){ delete[] Department;} void SetDep(char*);void SetNum(int num){ Number = num;} char *GetDep()const { return Department;} int GetNum()const { return Number;} void Show();};
//student.cpp #include “student.h” #include using namespace std;
Student::Student(char *name,int age,char sex,char *dep,int num): Person(name, age, sex){ Department = new char[strlen(dep)+1];strcpy(Department, dep);Number = num;}
Student::Student(Student &stu): Person(stu){ Department = new char[strlen(stu.Department)+1];strcpy(Department, stu.Department);Number = stu.Number;}
void Student::SetDep(char *dep){ delete[] Department;Department = new char[strlen(dep)+1];strcpy(Department, dep);}
void Student::Show(){ Person::Show();cout
4.4 多重继承
例1:X和Y是基类,Z从X和Y派生 cla X { public: int b;X(int k){ b=k;} };cla Y { public: int c;Y(int k){ c=k;} };cla Z: public X, public Y { public: int d;Z(int i,int j,int k):X(i),Y(j){ d=k;} } 例2:X和Y都从W派生而来 cla W { public: int a;W(int k){ d=k;} };cla X: public W { public: int b;X(int i, int k): W(i){ b=k;} };cla Y: public W { public: int c;Y(int i, int k): W(i){ c=k;} };cla Z: public X, public Y { public: int d;Z(int i, int j, int k, int l): X(i,j),Y(i,k){ d=l;} } int main(){ Z t(10,20,30,40);cout
例3:将W做为X和Y的虚基类 cla W { public: int a;W(int k){ a=k;} };cla X: virtual public W { public: int b;X(int i, int k): W(i){ b=k;} };cla Y: virtual public W { public: int c;Y(int i, int k): W(i){ c=k;} };cla Z: public X, public Y { public: int d;Z(int i, int j, int k, int l): W(i),X(i,j),Y(i,k){ d=l;} } int main(){ Z t(10,20,30,40);cout
(2)建立一个对象时,如果这个对象中含有从虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。该派生类的其他基类对虚基类构造函数的调用都自动被忽略。
(3)若同一层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数;(4)对于多个虚基类,构造函数的执行顺序仍然是先左后右,自上而下;(5)对于非虚基类,构造函数的执行顺序仍是先左后右,自上而下;(6)若虚基类由非虚基类派生而来,则仍然先调用基类构造函数,再调用派生类的构造函数。
4.5 赋值兼容规则
所谓赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。
附:线性表——顺序表
cla SeqList { private: int *data;int size;int MaxSize;public: SeqList(int sz=100);~SeqList(){ delete []data;} int Length()const { return size;} bool IsEmpty()const { return size==0;} void Insert(const int &x, int k);void Delete(int k);int GetData(int k)const;int Find(const int &x)const;void Show()const;};SeqList::SeqList(int sz){ MaxSize=sz;data=new int[MaxSize];size=0;}
void SeqList::Insert(const int &x, int k){ if(ksize+1){ cerr=k-1;i--)data[i+1]=data[i];data[k-1]=x;size++;}
void SeqList::Delete(int k){ if(size==0){ cerrsize){ cerr
int SeqList::GetData(int k)const { if(ksize){ cerr
int SeqList::Find(const int &x)const { for(int i=0;i
void SeqList::Show()const { for(int i=0;i
第5章 多态性
5.1 编译时的多态性与运行时的多态性
5.2 函数重载
5.3 运算符重载
例:复数类Complex //mycomplex.h #include using namespace std;cla Complex { private: double re, im;public: Complex(double r=0, double i=0){ re=r;im=i;} double real(){ return re;} double imag(){ return im;} Complex operator+(){ return *this;} Complex operator-(){ return Complex(-re,-im);} Complex &operator+=(Complex &);Complex &operator-=(Complex &);Complex &operator*=(Complex &);Complex &operator/=(Complex &);friend Complex operator+(Complex &, Complex &);friend Complex operator-(Complex &, Complex &);friend Complex operator*(Complex &, Complex &);friend Complex operator/(Complex &, Complex &);friend bool operator==(Complex &, Complex &);friend bool operator!=(Complex &, Complex &);friend ostream &operator>(istream &, Complex &);operator double(){ return re;} };//mycomplex.cpp
#include“mycomplex.h” #include using namespace std;
Complex &Complex::operator+=(Complex &c){ re += c.re;im += c.im;return *this;}
Complex &Complex::operator-=(Complex &c){ re-= c.re;im-= c.im;return *this;}
Complex &Complex::operator*=(Complex &c){ double t = re * c.rere * c.im)/ m;re = t;return *this;}
Complex operator+(Complex &a, Complex &b){ return Complex(a.re + b.re, a.im + b.im);}
Complex operator-(Complex &a, Complex &b){ return Complex(a.reb.im);}
Complex operator*(Complex &a, Complex &b){ return Complex(a.re * b.rea.re * b.im)/ m);}
bool operator==(Complex &a, Complex &b){ return a.re == b.re && a.im == b.im;}
bool operator!=(Complex &a, Complex &b){ return a.re!= b.re || a.im!= b.im;}
ostream &operator
istream &operator>>(istream &is, Complex &c){ is >> c.re >> c.im;return is;} 例:分数类 Fraction
#include using namespace std;
cla Fraction { private: int num, den;void reduce();public: Fraction(int n=0, int d=1);Fraction operator+(){ return *this;} Fraction operator-(){ return Fraction(-num, den);} Fraction &operator+=(Fraction &);Fraction &operator-=(Fraction &);Fraction &operator*=(Fraction &);Fraction &operator/=(Fraction &);Fraction &operator++();Fraction operator++(int);operator double();friend Fraction operator+(Fraction &, Fraction &);friend Fraction operator-(Fraction &, Fraction &);friend Fraction operator*(Fraction &, Fraction &);friend Fraction operator/(Fraction &, Fraction &);friend bool operator==(Fraction &, Fraction &);friend bool operator!=(Fraction &, Fraction &);friend bool operator(Fraction &, Fraction &);friend bool operator>=(Fraction &, Fraction &);friend ostream &operator>(istream &, Fraction &);};#include “fraction.h” #include using namespace std;Fraction::Fraction(int n, int d){ num = n;den = d;if(den==0)den = 1;reduce();} Fraction &Fraction::operator+=(Fraction &f){ num = num * f.den + den * f.num;den = den * f.den;reduce();return *this;} Fraction &Fraction::operator-=(Fraction &f){ num = num * f.denx.den * y.num, x.den * y.den);} Fraction operator*(Fraction &x, Fraction &y){ return Fraction(x.num * y.num, x.den * y.den);} Fraction operator/(Fraction &x, Fraction &y){ return Fraction(x.num * y.den, x.den * y.num);} bool operator==(Fraction &x, Fraction &y){ return(x.num * y.den == x.den * y.num);} bool operator!=(Fraction &x, Fraction &y){ return!(x == y);} bool operator x);} bool operator>(Fraction &x, Fraction &y){ return(y =(Fraction &x, Fraction &y){ return!(x >(istream &is, Fraction &f){ char ch;is >> f.num >> ch >> f.den;return is;} int gcd(int m, int n){ int k;while(n!= 0){ k = m % n;m = n;n = k;} return m;} void Fraction::reduce(){ if(den
5.4 类型转换
1、通过构造函数将别的类型转换为这个类的类型 如复数Complex类的构造函数 Complex(double r){ re=r;}
2、通过转换函数讲这个类的类型转换为别的类型 如在复数Complex类中的转换函数 operator double(){ return re;} 在分数Fraction类中的转换函数
operator double(){ return static_cast(num)/ den;}
用explicit关键字,可以禁止单个参数的构造函数用于自动类型转换,如 cla Stack { explicit Stack(int size);„ „ } Explicit也同样禁止用赋值来进行带有类型转换的初始化行为 如,不可以 Stack s=10;5.5 虚函数
1、引入派生类后的对象指针 例: cla A { public: void show(){ coutshow();pc=&b;pc->show();} 输出为AA
2、虚函数的定义及使用
例:引入虚函数后,上面的例子改为如下 cla A { public: virtual void show(){ coutshow();pc=&b;pc->show();} 输出为AB
3、纯虚函数和抽象类 例: cla A { public: virtual void show()=0;};cla B:public A { public: void show(){ coutshow();}
关于虚函数,有以下几点
1、如果成员函数是通过引用或指针,而不是通过对象来调用,那么,如果没有使用virtual,程序将根据引用类型或指针类型来选择方法;如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法。
2、如果要在派生类中重新定义基类的方法,则将它设置为虚拟方法,否则是指为非虚拟方法
3、如果使用指向对象的引用或指针来调用虚拟方法,程序将使用为对象类型定义的方法,而不使用为引用类型或指针类型定义的方法,这称为动态联编或晚期联编。
4、在基类方法的声明中使用virtual可使该方法在基类以及所有的派生类中都是虚拟的。
5、一个未在派生类中定义的纯虚函数仍旧还是一个纯虚函数,该派生类仍为一个抽象类。
6、通常应给基类提供一个虚拟析构函数,这样,当派生类对象结束时,将先调用派生的析构函数,再调用基类的析构函数。
7、如果派生类没有重新定义虚拟函数,则将使用该函数的基类版本。
8、如果重新定义继承的方法,应确保与原来的原型完全相同。但有一个例外,就是如果返回类型是基类指针或引用,则可改为指向派生类的指针或引用。实验基本C++程序设计 2 类和对象程序设计 3 派生与继承程序设计 4 运算符重载程序设计 5 模板程序设计 6 I/ O 流程序设计
《面向对象程序设计基础》教学大纲课程编号:课程中文名称:面向对象程序设计课程英文名称:Object-Oriented Programming 总学时: 40实验学时: 0上机学时:8 学分:2.5 适用专业:软件工......
《面向对象程序设计》实验教学大纲 课程总学时:64学分:4实验学时:16实验个数: 6个实验学分:1分 课程性质:专业必修课适用专业:计算机类专业 教材及参考书:《C++语言程序设计(第四版)》......
《面向对象程序设计实习》课程设计教学大纲课程编号: 学时:2周 学分:2 修课方式:必修 承担单位:软件学院 考核方式:考查一、课程设计的目的与任务1.课程设计目的(1)培养学生综合运用......
面向对象程序设计教程(C++语言描述)题解 第1章 面向对象程序设计概论一、名词解释 抽象 封装 消息 【问题解答】面向对象方法中的抽象是指对具体问题(对象)进行概括,抽出一类对象......
C#面向对象程序设计感想本课程主要讲解了控件,资源管理器,文件流,线程等等,通过这门课的学习,我学到了一些应用性的知识,比如如何设计控件,对文件流进行程序的代码编写,还有就是多线......