多态,虚函数,纯虚函数 , 虚析构函数 ,抽象类

多态

多态:是对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现;在程序编译时多态性体现在函数和运算符的重载上;

虚函数

虚函数:在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。允许在派生类中对基类的虚函数重新定义。

虚函数是运行时多态,若某个基类函数声明为虚函数,则其公有派生类将定义与其基类虚函数原型相同的函数,这时,当使用基类指针或基类引用(虚函数只能借助于指针或者引用来达到多态的效果)操作派生类对象时,系统会自动用派生类中的同名函数代替基类虚函数。

//没有用虚函数:

#include <iostream>
using namespace std;

//定义基类Animal
class Animal       
{
public:
    //基类speak()函数
    void speak(){ cout << "animal language!" << endl; }
};

//定义派生类Cat
class Cat :public Animal   
{
public:
    //定义与基类同名的函数speak()
    void speak(){ cout << "cat language: miaomiao!" << endl; }
};

int main()
{
    //定义派生类对象cat
    Cat cat;  
    //定义基类指针并指向派生类对象                                        
    Animal *panimal = &cat;  
    //通过指针调用speak()函数                     
    panimal->speak();                              
    system("pause");
    return 0;
}
////运行结果:animal language!
////原因:派生类继承并改写了speak(),但这种改变在静态编联的条件下编译器并不知道,若想通知编译器这种改变,则需要通过动态编联实现,其方法就是虚函数

//采用虚函数:

#include <iostream>
using namespace std;

//定义基类Animal
class Animal                                            
{
public:
    //定义虚函数speak()
    virtual void speak(){ cout << "animal language!" << endl; }
};

//定义派生类Cat
class Cat :public Animal                             
{
public:
    //定义Cat类自己的虚函数speak()
    virtual void speak(){ cout << "cat language: miaomiao!" << endl; }
};
int main()
{
    //定义派生类对象cat
    Cat cat;  
    //**定义基类指针并初始化为cat地址**                                         
    Animal *panimal = &cat;   
    //**定义基类引用,初始化为cat**                      
    Animal &ref = cat;  
    //通过panimal指针调用speak()函数                             
    panimal->speak();  
    //通过引用ref调用speak()函数                              
    ref.speak();                                      
    system("pause");
    return 0;
}
//运行结果:cat language: miaomiao!
//cat language: miaomiao!

虚析构函数

虚析构函数
在C++中,不能声明虚构造函数,因为构造函数执行时,对象还没有构造好,不可按虚函数方式进行调用,但可以声明虚析构函数。

使用基类指针指向一个new生成的派生类对象,通过delete销毁基类指针指向的派生类对象时,有以下两种情况:
(1)如果基类虚构函数不是虚析构函数,则只会调用基类的析构函数,派生类的析构函数不被调用,此时派生类重申请的资源不被收回。
(2)如果基类析构函数为虚析构函数,则释放基类指针指向的对象时会调用基类及派生类虚构函数,派生类对象中所有的资源被回收。

#include <iostream>
using namespace std;
//定义基类Animal
class Animal                                                
{
public:
    //声明基类构造函数
    Animal(char *name);  
    //声明print_name()函数                                 
    void print_name();   
    //声明虚函数print_color()                                 
    virtual void print_color();  
    //声明虚函数speak()                       
    virtual void speak();    
    //声明析构函数                            
    virtual ~Animal();                                    
private:
    //存放动物名称的数据成员
    char *m_pAnimalName;                                 
};
//Animal类构造函数的定义
Animal::Animal(char *name)                               
{
    int len = strlen(name) + 1;
    //为m_pAnimalName指针开辟空间
    m_pAnimalName = new char[len];   
    //存入动物名称                  
    strcpy_s(m_pAnimalName, len, name);               
}
//Animal类析构函数
Animal::~Animal()                                         
{
    cout << "Animal destructor!" << endl;
    if (m_pAnimalName){
        //释放空间
        delete[] m_pAnimalName;                         
    }
}
//显示动物名称
void Animal::print_name()                               
{
    cout << "name:" << m_pAnimalName << endl;
}
//定义虚函数print_color(),本函数在基类中为空函数,需要在派生类中重定义
void Animal::print_color()
{

}
void Animal::speak()
{
    cout << "animal language!" << endl;
}
//定义派生类Cat
class Cat :public Animal                                  
{
public:
    Cat(char* name, char *catcolor);
    //声明虚函数print_color()
    virtual void print_color();  
    //声明虚函数speak()                      
    virtual void speak();                               
    virtual ~Cat();
private:
    //存放猫的颜色的数据成员
    char *m_pCatColor;                                   
};
//Cat类构造函数的定义
Cat::Cat(char* name, char *color) :Animal(name)     
{
    cout << "Cat constructor!" << endl;
    //为m_pCatcolor指针开辟空间
    m_pCatColor = new char[strlen(color) + 1];  
    //存入描述猫颜色自的字符串
    strcpy_s(m_pCatColor, strlen(color) + 1, color); 
}
//Cat类析构函数的定义
Cat::~Cat()                                             
{
    cout << "Cat destructor!" << endl;
    if (m_pCatColor){
        //释放m_pCatcolor指向的空间
        delete[] m_pCatColor;                        
    }
}
//print_color()虚函数的实现
void Cat::print_color()                               
{
    cout << "cat color :" << m_pCatColor << endl;
}
//speak()虚函数的实现
void Cat::speak()                                      
{
    cout << "cat language: miaomiao!" << endl;
}
int main()
{
    //定义基类Animal指针数组
    Animal *p[2];                                      
    int i;
    //通过new生成派生类Cat对象
    p[0] = new Cat("short_haired_cat", "white");
    p[0]->print_name();
    p[0]->print_color();
    p[0]->speak();
    //通过new生成派生类Cat对象
    p[1] = new Cat("persian_cat", "brown");     
    p[1]->print_name();
    p[1]->print_color();

    for (i = 0; i < 2; i++)
        //通过delete释放派生类对象
        delete p[i];                                  
    system("pause");
    return 0;
}

纯虚函数

纯虚函数的作用:在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。作为接口而存在 纯虚函数不具备函数的功能,一般不能直接被调用。
定义:virtual 函数返回值类型 函数名(参数表) = 0;
注意一点是,抽象类是无法进行实例化对象的!

#include <iostream>
using namespace std;

//定义基类Animal
class Animal                                            
{
public:
    //声明基类构造函数
    Animal(char *name); 
    //声明print_name()函数                              
    void print_name();
    //声明纯虚函数print_color()                                
    virtual void print_color() = 0;  
    //声明虚析构函数              
    virtual ~Animal();                               
private:
    //存放动物名称的数据成员
    char *m_pAnimalName;                             
};

//Animal类构造函数的定义
Animal::Animal(char *name)                          
{
    int len = strlen(name) + 1;
    //为m_pAnimalName指针开辟空间
    m_pAnimalName = new char[len]; 
    //存入动物名称                
    strcpy_s(m_pAnimalName, len, name);           
}

//Animal类析构函数
Animal::~Animal()                                     
{
    cout << "Animal destructor!" << endl;
    if (m_pAnimalName){
        //释放空间
        delete[]m_pAnimalName;                     
    }
}
//定义print_name()函数
void Animal::print_name()                           
{
    cout << "name:" << m_pAnimalName << endl;
}
//定义派生类Cat
class Cat :public Animal                             
{
public:
    Cat(char* name, char *catcolor);
    //声明虚函数print_color()
    virtual void print_color();   
    //声明虚析构函数                
    virtual ~Cat();                                  
private:
    //存放猫颜色的数据成员
    char *m_pCatColor;                               
};
//Cat类构造函数的定义
Cat::Cat(char* name, char *color) :Animal(name) 
{
    cout << "Cat constructor!" << endl;
    //为m_pCatColor指针开辟空间
    m_pCatColor = new char[strlen(color) + 1]; 
    //存入描述猫颜色的字符串   
    strcpy_s(m_pCatColor, strlen(color) + 1, color);  
}
//Cat类析构函数的定义
Cat::~Cat()                                             
{
    cout << "Cat destructor!" << endl;
    if (m_pCatColor){
        //释放m_pCatColor指向的空间
        delete[]m_pCatColor;                         
    }
}
//print_color()虚函数的实现
void Cat::print_color()                              
{
    cout << "cat color :" << m_pCatColor << endl;
}
int main()
{
    //定义基类Animal指针数组
    Animal *p;                                         
    //通过new生成派生类Cat对象
    p = new Cat("short_haired_cat", "white");   
    p->print_name();
    p->print_color();
    cout << "--------------------" << endl;
    //通过delete释放派生类对象
    delete p;                                         
    system("pause");
    return 0;
}

抽象类

从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。

抽象类的作用:
抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。

使用抽象类时注意:
• 抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。
• 抽象类是不能定义对象的。

接口类

接口类:在类中仅含有纯虚函数的类。这点包含两个信息,其一是只有成员函数,其二是该成员函数都是虚函数。接口类更多是作为一种协议。

#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;

/**
 * 定义射击类:CanShut
 * 定义纯虚函数:aim、reload
 */
class CanShut//接口类,只含有纯虚函数
{
public:
    virtual void aim() =0;
    virtual void reload() =0;//纯虚函数
};

/**
 * 定义枪类:Gun
 * 公有继承射击类
 * 实现成员函数:aim、reload
 */
class Gun : public CanShut
{
public:
    virtual void aim()
    {
         cout << "Gun -- aim" << endl;
    }
    virtual void reload()
    {
         cout << "Gun -- reload" << endl;
    }
};

/**
 * 定义含参函数射击:hunting
 * 调用参数的aim与reload函数
 */
void hunting(CanShut *s)<span style="display: none; width: 0px; height: 0px;" id="transmark"></span>
{
    s->aim();
    s->reload();
}

int main(void)
{
    // 实例化枪对象
    CanShut *g1=new Gun;
    // 调用含参函数hunting,将对象枪传入函数中
    hunting(g1);
    // 释放内存
    delete g1;
    g1=NULL;
    return 0;
}

参考:
1.C++面试出现频率最高的30道题目(一)
2.C++学习笔记之多态(虚函数)
3.虚函数和纯虚函数的区别
4.《C++程序设计教程》–传智播客

猜你喜欢

转载自blog.csdn.net/fengying2016/article/details/77585221
今日推荐