欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

虚函数与多态性

程序员文章站 2022-04-21 23:30:28
...

一.静态联编

1.联编是指一个程序自身彼此关联的过程,在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作(函数)的代码段之间的映射关系; 就是把函数调用与函 数的程序代码连接(联系)在一起的过程。
2.联编分为两大类
1)静态联编
调用速度快,效率高,但缺乏灵活性。
C++为了兼容C语言仍然是编译型的,采用静态联编。
2)动态联编
运行效率低,但增强了程序灵活性。
为了实现多态性,利用虚函数机制,可部分地采用动态联编。

二.类指针的关系

基类指针和派生类指针与基类对象和派生类对象4种可能匹配:
1.直接用基类指针引用基类对象
2.直接用派生类指针引用派生类对象
3.用基类指针引用一个派生类对象
4.用派生类指针引用一个基类对象

(一)基类指针引用派生类对象

虚函数与多态性

A * p ; // 指向类型 A 的对象的指针
A A_obj ; // 类型 A 的对象
B B_obj ; // 类型 B 的对象
p = & A_obj ;// p 指向类型 A 的对象
p = & B_obj ;// p 指向类型 B 的对象,它是 A 的派生类

(二)派生类指针引用基类对象
1.不能将一个声明为指向派生类对象的指针指向其基类的对象。
2.派生类指针只有经过强制类型转换之后,才能引用基类对象

三.虚函数与动态联编

(一)实现动态联编方式的前提
1.先要声明虚函数
2.类之间满足赋值兼容规则:派生类公有继承基类
3.通过指针与引用来调用虚函数。
(二)虚函数

  1. 冠以关键字 virtual 的成员函数称为虚函数
  2. 实现运行时多态的关键首先是要说明虚函数
  3. 必须用基类指针调用派生类的不同实现版本

虚函数的重载特性
在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、参数类型和顺序完全相同
注意:
1.构造函数不能是虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数。
2.析构函数可以是虚的。虚析构函数用于指引 delete 运算符正确析构动态对象。
3.虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态函数
4.构造函数、内联成员函数、静态成员函数不能是虚函数。(虚函数不能以内联的方式进行处理)

虚函数与多态性
(三)虚析构函数

1.构造函数不能是虚函数
2.析构函数可以是虚的。虚析构函数用于指引 delete 运算符正确析构动态对象。

例,普通析构函数在删除动态派生类对象的调用情况

#include<iostream>
using namespace std ;
class A { public:
virtual~A()
{ cout << "A::~A() is called.\n" ; } 
} ;
class B : public A { public:
~B()
{ cout << "B::~B() is called.\n" ; } 
} ;
int main() { A *Ap = new B ; B *Bp2 = new B ;
cout << "delete first object:\n" ;
delete Ap;
cout << "delete second object:\n" ;
delete Bp2 ;
}

四.纯虚函数和抽象类

1.纯虚函数是一种特殊的虚函数,是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本
2.纯虚函数为各派生类提供一个公共界面
3. 纯虚函数说明形式:
virtual 类型 函数名(参数表)= 0 ;
4. 一个具有纯虚函数的基类称为抽象类。
5.纯虚函数的作用:
在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。

例.简单图形类

#include<iostream>
using namespace std ;
#include"figure.h"
class figure
{ protected : double x,y;
public: void set_dim(double i, double j=0) { x = i ; y = j ; }
virtual void show_area() = 0 ; };
class triangle : public figure
{ public :
void show_area()
{ cout<<"Triangle with high "<<x<<" and base "<<y <<" has an area of
"<<x*0.5*y<<"\n"; } };
class square : public figure
{ public:
void show_area()
{ cout<<"Square with dimension "<<x<<"*"<<y <<" has an area of
"<<x*y<<"\n"; } };
class circle : public figure
{ public:
void show_area()
{ cout<<"Circle with radius "<<x;
cout<<" has an area of "<<3.14*x*x<<"\n"; } };
virtual void show_area() = 0 ; //纯虚函数
void show_area()
{ cout<<"Triangle with high "<<x<<" and base" 
<<y <<" has an area of "<<x*0.5*y<<"\n"; }
void show_area()
{ cout<<"Square with dimension "<<x<<"*"<<y
<<" has an area of "<<x*y<<"\n"; }
void show_area()
{ cout<<"Circle with radius "<<x;
cout<<" has an area of "<<3.14*x*x<<"\n";}};
int main()
{ triangle t ; //派生类对象
square s ; circle c;
t.set_dim(10.0,5.0) ;
t.show_area();
s.set_dim(10.0,5.0) ;
s.show_area() ;
c.set_dim(9.0) ;
c.show_area() ;
}

五.虚函数与多态的应用

虚函数与多态性

#include<iostream>
#include<cstring>
#include<iomanip>
using namespace std ;
class Employee
{
public:
    Employee(const long k,const char* str )
    {
        number = k;
        strcpy(name,str);
    }
    virtual ~Employee()
    {
        name[0] = '\0';
    }
    const char * getName() const
    {
        return name;
    }
    const long getNumber() const
    {
        return number;
    }
    virtual double earnings() const=0;
    virtual void print() const
    {
        cout <<number<<setw(20)<<name;
    }
protected:
    long number;
    char name[20];
};
class Manager : public Employee
{
public:
    Manager(const long k,const char * str, double salary=0.0):
        Employee(k,str)
    {
        setMonthlySalary(salary);
    }
    ~Manager() { }
    void setMonthlySalary(double salary)
    {
        monthlySalary = salary;
    }
    virtual double earnings() const
    {
        return monthlySalary;
    }
    virtual void print() const
    {
        Employee::print();
        cout<<setw(16)<<"Manager\n";
        cout<<" earned $"<<earnings()<<endl;
    }
private:
    double monthlySalary;
};
class HourlyWorker : public Employee
{
public:
    HourlyWorker(const long k,const char * str,double w=0.0,int h=0): Employee(k,str)
    {
        setWage(w);
        setHours(h);
    }
    ~HourlyWorker() {}
    void setWage(double w)
    {
        wage = w;
    }
    void setHours(int h)
    {
        hours = h;
    }
    virtual double earnings() const
    {
        return wage * hours;
    }
    virtual void print() const
    {
        Employee::print();
        cout<<setw(16)<<"Hours Worker\n"<<"\t\twageperhour "<<wage<<" Hours "<<hours;
        cout<<" earned $"<<earnings()<<endl;
    }
private:
    double wage;
    double hours;
};
class PieceWorker : public Employee
{
public:
    PieceWorker(const long k,const char *str,double wage=0.0,int quantity=0):
        Employee(k,str)
    {
        setWage(wage);
        setQuantity(quantity);
    }
    ~PieceWorker() { }
    void setWage ( double wage )
    {
        wagePerPiece = wage;
    }
    void setQuantity ( int q)
    {
        quantity = q;
    }
    virtual double earnings() const
    {
        return wagePerPiece * quantity;
    }
    virtual void print() const
    {
        Employee::print();
        cout<<setw(16) <<"Piece Worker\n";
        cout<<"\t\twagePerPiece "<< wagePerPiece<<" quantity "<<quantity;
        cout<<" eared $"<< earnings() <<endl;
    }
private:
    double wagePerPiece;
    int quantity;
};
void test1()
{
    cout << setiosflags(ios::fixed|ios::showpoint) << setprecision(2) ;
    Manager m1 ( 10135, "Cheng ShaoHua", 1200 ) ;
    Manager m2 ( 10201, "Yan HaiFeng");
    m2.setMonthlySalary ( 5300 ) ;
    HourlyWorker hw1 ( 30712, "Zhao XiaoMing", 5, 8*20 ) ;
    HourlyWorker hw2 ( 30649, "Gao DongSheng" ) ;
    hw2.setWage ( 4.5 ) ;
    hw2.setHours ( 10*30 ) ;
    PieceWorker pw1 ( 20382, "Xiu LiWei", 0.5, 2850 ) ;
    PieceWorker pw2 ( 20496, "Huang DongLin" ) ;
    pw2.setWage ( 0.75 ) ;
    pw2.setQuantity ( 1850 ) ;
    Employee *basePtr;
    basePtr=&m1;
    basePtr->print();
    basePtr=&m2;
    basePtr->print();
    basePtr=&hw1;
    basePtr->print();
    basePtr=&hw2;
    basePtr->print();
    basePtr=&pw1;
    basePtr->print();
    basePtr=&pw2;
    basePtr->print();
}
int main()
{
    test1();
    return 0;
}

六.异质链表

1.把不同类对象统一组织在一个数据结构中,可以定义抽象类指针数组或链表。
2.由于这种表中的具有不同类类型元素(它们都有共同的基类),所以称为“异质表”。