C++(例題集—簡單解析-多型)
運算子過載
例題7-1
#include<iostream> using namespace std; class Complex{ double real; double imag; public: Complex(double r1=0,double img=0):real(r1),imag(img){} friend Complex add(const Complex &left,const Complex &right); void show(){ cout<<real<<","<<imag<<endl; } }; Complex add(const Complex <,const Complex& rt){ return Complex(lt.real+rt.real,lt.imag+rt.imag); } int main(){ Complex c1(1,2),c2(3,4),c; //c=c1+c2; c=add(c1,c2); c.show(); return 0; }
例題7-2
#include<iostream> using namespace std; class Complex{ double real; double imag; public: Complex(double r=0,double i=0):real(r),imag(i){} friend Complex operator +(const Complex &L,const Complex &R); void show(){ cout<<real<<","<<imag<<endl; } }; Complex operator +(const Complex &L,const Complex &R){ return Complex(L.real+R.real,L.imag+R.imag); } int main() { Complex c1(1,2),c2(3,4),c; c=c1+c2; c.show(); return 0; }
例題:過載+
#include<iostream> using namespace std; class Complex{ double real; double imag; public: Complex(double r=0,double i=0):real(r),imag(i){} Complex operator +(const Complex &r); void show(){ cout<<"("<<real<<","<<imag<<")\n"; } }; Complex Complex::operator +(const Complex &r){ return Complex(real+r.real,imag+r.imag); } int main() { Complex c1(1,2),c2(3,4),c; c=c1+c2; c.show(); return 0; }
例題:過載複數==:
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r1=0,double img=0):real(r1),imag(img){}
friend bool operator ==(const Complex &L,const Complex &R);
};
bool operator==(const Complex &L,const Complex &R){
return (L.real==R.real&&L.imag==R.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c3(1,2);
if(c1==c2){
cout<<"C1==C2"<<endl;
}else{
cout<<"C1!=C2"<<endl;
}
if(c1==c3){
cout<<"C1==C3"<<endl;
}else{
cout<<"C1!=C3"<<endl;
}
return 0;
}
把上面的過載變成 成員函式:
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r1=0,double img=0):real(r1),imag(img){}
bool operator ==(const Complex &R);
};
bool Complex :: operator==(const Complex &R){
return (real==R.real&&imag==R.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c3(1,2);
if(c1==c2){
cout<<"C1==C2"<<endl;
}else{
cout<<"C1!=C2"<<endl;
}
if(c1==c3){
cout<<"C1==C3"<<endl;
}else{
cout<<"C1!=C3"<<endl;
}
return 0;
}
過載運算子<<為日期類Date的友元函式,輸出日期.
#include<iostream>
#include<cstring>
using namespace std;
class Date{
int Y,M,D;
public:
Date(int ye,int mn,int day):Y(ye),M(mn),D(day){}
friend ostream & operator <<(ostream &out,Date &date);
};
ostream &operator<<(ostream &out,Date &date){
out<<date.Y<<" - "<<date.M<<" - "<<date.D<<endl;
return out;
}
int main()
{
Date d1(2014,01,25),d2(2017,02,35);
cout<<d1<<d2;
return 0;
}
過載運算子:++前置,++後置,<<流運算.
#include<iostream>
#include<cstring>
using namespace std;
class Time{
int H,M,S;
public:
Time (int h=0,int m=0,int s=0):H(h),M(m),S(s){}
Time &operator++();
Time operator++(int);
friend ostream &operator <<(ostream &out,Time &time);
};
Time &Time::operator++(){
S=(S+1)%60;
if(S==0){
if(M==59)
H=(H+1)%24;
M=(M+1)%60;
}
return (*this);
}
Time Time::operator++(int){
Time old=*this;
S=(S+1)%60;
if(S==0){
if(M==59)
H=(H+1)%24;
M=(M+1)%60;
}
return old;
}
ostream& operator<<(ostream &out,Time &time){
out<<time.H<<":"<<time.M<<":"<<time.S;
return out;
}
int main()
{
Time t(11,59,58);
for(int i=0;i<4;i++){
t++; cout<<t<<endl;
//cout<<t++<<endl;
}
cout<<endl;
for(int i=0;i<3;i++){
cout<<++t<<endl;
}
return 0;
}
子類與基類的相容性
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class Student{
string name;
int age;
double score;
public:
Student (string nm,int age,double score);
void display()const ;
};
Student::Student(string nm,int a,double s):name(nm),age(a),score(s){};
void Student::display()const{
cout<<"姓名:"<<name<<",年齡:"<<age<<",分數"<<score<<endl;
}
class Graduate:public Student{
string sy;
public:
Graduate(string name,int age,double score,string ss);
void display()const;
};
Graduate::Graduate(string nm,int a,double s,string ss):Student(nm,a,s),sy(ss){};
void Graduate::display() const{
Student::display();
cout<<"專業:"<<sy<<endl;
}
int main()
{
Student st("李強",18,95);
Graduate gt("高原",25,93,"軟體工程");
st.display();
gt.display();
st=gt;
st.display();
Student &rs=gt;
rs.display();
Student *ps;
ps=>
ps->display();
return 0;
}
子類物件呼叫父類成員函式:
#include<iostream>
using namespace std;
class Bird{
public:
void singing(){
cout<<"bird singing...."<<endl;
}
};
class Sparrow:public Bird{
public:
void singing(){
cout<<"Sparrow jiji zha....."<<endl;
}
};
class Crow:public Bird{
public:
void singing(){
cout<<"Crow GuGuGuGuGu....."<<endl;
}
};
int main()
{
Bird bird;
Sparrow sparrow;
Crow crow;
bird.singing();
sparrow.singing();
crow.singing();
sparrow.Bird::singing();
return 0;
}
例題7-7 用迴圈來實現例題7-6(反例)
大家通過執行就明白了什麼回事了,因為這個它只有父類指標,指著只有父類的位置來展示。
所以執行一下程式碼就變成全部是 Bird singing....
#include<iostream>
using namespace std;
class Bird{
public:
void singing(){
cout<<"bird singing...."<<endl;
}
};
class Sparrow:public Bird{
public:
void singing(){
cout<<"Sparrow jiji zha....."<<endl;
}
};
class Crow:public Bird{
public:
void singing(){
cout<<"Crow GuGuGuGuGu....."<<endl;
}
};
void sing(Bird *bird){
bird->singing();
}
int main()
{
Bird bird;
Sparrow sparrow;
Crow crow;
Bird *p[]={&bird,&sparrow,&crow};
//bird.singing();
//sparrow.singing();
//crow.singing();
//sparrow.Bird::singing();
for(int i=0;i<3;i++){
sing(p[i]);
}
return 0;
}
通過上面的示例缺少了個體的特性,所以引入了虛擬函式的概念。
虛擬函式的作用
引例:
#include<iostream>
using namespace std;
class Base{
public:
virtual void show(){
cout<<"showing base.\n";
}
};
class D:public Base{
public:
virtual void show(){
cout<<"showing D.\n";
}
};
int main()
{
Base base;
D d;
Base *p=&d;
p->show(); // 輸出“ D ”
Base &r=d; // 輸出“ D ”同上,上面用的是指標訪問,而這個是引用來實現訪問。
r.show();
base=d; //但是子類物件賦值基類物件後,基類物件呼叫的仍然是基類的虛擬函式.
base.show(); //輸出“ Base ”
return 0;
}
例題7-9 虛擬函式的多型性
利用了虛擬函式來改善了例題7-7的弊端。
#include<iostream>
using namespace std;
class Bird{
public:
virtual void singing(){
cout<<"bird singing.....\n";
}
};
class Sparrow:public Bird{
public:
virtual void singing(){
cout<<"sparrow jijizha ....\n";
}
};
class Crow:public Bird{
public:
virtual void singing(){
cout<<"Crow GuGuGuGuGuGu ....\n";
}
};
void sing(Bird *bird){
bird->singing();
}
void sing(Bird &rb){
rb.singing();
}
void sing2(Bird bird){
bird.singing();
}
int main(){
Bird bird;
Sparrow sparrow;
Crow crow;
sing2(sparrow); //輸出“Bird jijizha ..."
// 和例題7-6犯了一樣的錯誤。只能輸出父類中的singing()
sing(sparrow); //輸出“sparrow jijizha ..."
Bird *p[]={&bird,&sparrow ,&crow};
for(int i=0;i<3;i++){
sing(p[i]); //依次輸出“Bird/sparrow/Crow jijizha ..."
}
return 0;
}
例題7-10 人Person派生學生類,學生類派生研究生類Graduate;
#include<iostream>
#include<cstring>
using namespace std;
class Person{
char *name;
bool isMale;
int age;
public:
Person(char *name,bool isMale, int initage);
~Person(){
delete []name;
}
virtual void show()const;
};
Person::Person(char *nm,bool isM,int a):isMale(isM),age(a){
name=new char[strlen(nm)+10];
strcpy(name,nm);
}
void Person::show()const{
cout<<name<<",";
if(isMale)cout<<"男";
else cout<<"女";
cout<<","<<age<<"歲";
}
class Student :public Person{
double score;
public:
Student(char *name,bool isMale,int initAge,double initScore);
virtual void show()const;
};
Student::Student(char *nm,bool ism,int a,double s):Person(nm,ism,a),score(s){}
void Student::show() const{
Person::show();
cout<<"分數:"<<score;
}
class Graduate:public Student{
char sy[20];
public:
Graduate(char *name,bool isMale,int initage,double initScore,char spy[]);
void show()const;
};
Graduate::Graduate(char *nm,bool ism,int a,double s,char spy[]):Student(nm,ism,a,s){
strcpy(sy,spy);
}
void Graduate::show() const{
Student::show();
cout<<",專業:"<<sy<<endl;
}
void fun(Person *person){
person->show();
}
int main ()
{
Person psn("高峰",true,20);
Student st("李紅",false,18,95);
Graduate gt("王濤",true,25,95,"電子學");
Person *p[]={&psn,&st,>};
for(int i=0;i<3;i++){
fun(p[i]);
cout<<endl;
}
return 0;
}
解析:基類Person中宣告虛擬函式Show(),子類Student和Graduate中的同名函式自動成為虛擬函式,定義
一個fun()函式,函式形參為基類指標,函式的作用是呼叫show()虛擬函式.當基類指標指向子類時,
因呼叫的是虛擬函式,所以子類顯示了學生和研究生各自的特性.
當類族中某個成員函式定義為虛擬函式時,物件與函式的繫結是在執行時實施的.雖然這種後繫結能夠
實現執行時的多型效應,但這種繫結會增加程式執行的開銷,且有若干限制條件.
( 1 )、靜態成員函式不能宣告為虛擬函式,因為靜態成員屬於類,不專屬於某個物件。
( 2 )、行內函數不能宣告為虛擬函式,因為行內函數在編譯是已被明確的執行程式碼替換。
( 3 )、建構函式不能是虛擬函式。建構函式進行物件初始化是,物件的狀態尚未完全確定。
例題7-11 虛解構函式
#include<iostream>
using namespace std;
class Base{
public:
~Base(){ //virtual ~Base() 目前沒有把解構函式定義為虛擬函式.
cout<<"呼叫了 Base 解構函式"<<endl;
}
};
class D:public Base{
int *p;
public:
D(){
p=new int(5);
}
~D(){
cout<<"呼叫了 D 的解構函式"<<endl;
delete p;
}
};
void fun(Base *pb){
delete pb;
}
int main()
{
Base *b=new D();
fun(b);
// 若沒定義虛擬函式則輸出 “呼叫了Base 解構函式”;
// 若定義了則輸出 “呼叫了 D 解構函式”
// “呼叫了Base解構函式”
return 0;
}
結果顯示:
在基類的解構函式沒有宣告為虛擬函式時,派生類的解構函式沒有呼叫,派生類物件動態開闢的記憶體
沒有釋放,造成了記憶體洩漏。
將基類的解構函式改為虛解構函式後,解構函式具有了多型效應,程式呼叫了不同的解構函式。
純虛擬函式和抽象類
抽象類例子:
#include<iostream>
#include<cstring>
using namespace std;
class P{
char name[10];
int age;
public:
P(char name[],int age);
virtual void exercise()=0;
virtual void show();
};
class BP:public P{
int bage;
public:
BP(char name[],int age,int bage);
virtual void exercise()=0;
virtual void show();
};
class FP:public BP{
public:
FP(char name[],int age,int bage);
virtual void exercise();
};
class BsP:public BP{
public:
BsP(char name[],int age,int bage);
virtual void exercise();
};
class VP:public BP{
public:
VP(char nm[],int age,int bage);
virtual void exercise();
};
P::P(char nm[],int a):age(a){
strcpy(name,nm);
}
void P::show(){
cout<<name<<","<<age<<"歲.";
}
BP::BP(char nm[],int a,int bAge):P(nm,a),bage(bAge){}
void BP::show(){
P::show();
cout<<"球齡:"<<bage<<"年 .";
}
FP::FP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void FP::exercise(){
cout<<" 踢足球.\n";
}
BsP::BsP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void BsP::exercise(){
cout<<" 打籃球.\n" ;
}
VP::VP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void VP::exercise(){
cout<<" 打排球.\n" ;
}
void play(P& player){
player.show();
player.exercise();
}
int main(){
FP fplay("高峰",20,8);
BsP bplay("王強",19,7);
VP vplay("張麗",18,6);
play(fplay);
play(bplay);
play(vplay);
return 0;
}
程式中基類運動員"練習"exercise()是抽象的運動,無法具體實現,所以函式exercise()宣告為類Player的純虛擬函式,
因此類player為抽象基類.抽象類P 不能例項化,只有子類球員BP才能具體說明球齡,但函式exercise()仍無法具體實現,
因此類BP依然為抽象類。直到子類足球運動員,籃球運動員和排球運動員是,父類的純虛擬函式exercise()才能具體實現,
才可以建立各自的物件,展示各自的行為
例題7-13 將形狀Shape設計成抽象類,實現執行時的多型.
#include<iostream>
using namespace std;
class Shape{
public:
virtual char *getName()=0;
virtual double getArea()=0;
};
class T:public Shape{
double width,height;
public:
T(double w,double h):width(w),height(h){}
char *getName(){
return "三角形";
}
double getArea(){
return (0.5*width*height);
}
};
class R:public Shape{
double width,length;
public:
R(double wid,double len):width(wid),length(len){}
char *getName(){
return "長方形";
}
double getArea(){
return width*length;
}
};
int main()
{
Shape *ps;
T t(10,5);
R r(2,8);
ps=&t;
cout<<"形狀:"<<ps->getName()<<",面積:"<<ps->getArea()<<endl;
ps=&r;
cout<<"形狀:"<<ps->getName()<<",面積:"<<ps->getArea()<<endl;
return 0;
}
模板
找到兩個數,三個數裡面的最大值
#include<iostream>
using namespace std;
template<typename T >T maxz(T x,T y);
template<typename S >S maxz(S x,S y,S z);
int main()
{
cout<<maxz(2,5)<<endl;
cout<<maxz(2.9,6.2)<<endl;
cout<<maxz(1,2,3)<<endl;
return 0;
}
template<typename T >T maxz(T x,T y){
return x>y?x:y;
}
template<typename S >S maxz(S x,S y,S z){
S temp=maxz(x,y);
return temp>z?temp:z;
}
模板類
#include<iostream>
using namespace std;
template <class T1,class T2>
class Myclass{
T1 x;
T2 y;
public:
Myclass(T1 a,T2 b):x(a),y(b){}
void show();
};
template <class T1,class T2>void Myclass<T1,T2>::show(){
cout<<"X="<<x<<"\tY="<<y<<endl;
}
int main()
{
Myclass<int,char>obj1(4,'w');
Myclass<double ,char >obj2(5.8,'w');
obj1.show();
obj2.show();
return 0;
}