c++多态实现与函数模板 笔记

实现多态的必要条件

1> 函数重写
2> 虚函数
3> 父类指针指向子类对象

函数重写

在子类中定义与父类原型相同的函数
原型相同:函数名、参数(参数个数、参数类型)必须一致,但是,函数体不同
注意:函数重写发生在父子类直接

辨析:重载、重写

重载:函数名相同、形参列表必须不同,发生在同一个类中
重写:函数名相同、形参列表必须相同,发生在不同类中

虚函数

当父类指针或者引用指向子类对象,并且想要通过父类指针或引用调用
子类中的函数时,那么需要将该函数在父类中进行定义,并且设置为虚函数。
其他:
不使用或者没有父类的指针或引用指向子类对象时,则用不到虚函数,
父类一旦设置了虚函数,就会形成一个虚函数表,子类的重写函数都会记到表里;设置父类的引用目标为子类时,通过引用目标访问到的就是子类的函数。
#include <iostream>

using namespace std;

class Animal
{
protected:
    string name;
    string food;      //食物
public:
    Animal() {}
    Animal(string n, string f):name(n), food(f) {}

    virtual void voice()
    {
       //虚函数表,virtual的功能是建立一个虚函数表,并创建一个指针指向这个表
        //子类继承时,也会继承这个虚函数表,当子类有自己的函数,子类定义的对象会通过
        //指针去表中找自己对应的函数,如果此时还想用父类的函数,可以在函数名前加作用域限定符
    }
    //纯虚函数存在,该类为抽象类(不能实例化类对象。但是可以设置引用,指针);
};

class Sheep : public Animal
{
private:
    int leg;         //腿的个数

public:
    Sheep() {}
    Sheep(string n, string f, int l):Animal(n, f), leg(l) {}

    void voice()override
    {
        //override关键字用来确保虚函数存在
        cout<<name<<"   "<<food<<"   "<<leg;
        cout<<"   mie mie mie..."<<endl;
    }
};

class Wolf : public Animal
{
private:
    int tail;         //尾巴的个数

public:
    Wolf() {}
    Wolf(string n, string f, int t):Animal(n, f), tail(t) {}

    void voice() override
    {
        cout<<name<<"   "<<food<<"   "<<tail;
        cout<<"   wu wuu wuuu..."<<endl;
    }
};


void print(Animal & a)
{
    //引用的作用,实现多态
    a.voice();
}



int main()
{
    Sheep s("xiyy", "gress", 4);
    s.voice();
    s.Animal::voice();
//此处通过父类的作用域限定符可以调用父类的函数
    cout<<"7777"<<endl;
    Wolf w("xiaohh", "meat", 1);
    w.voice();

    cout<<"*******************************"<<endl;
    print(s);      //羊的叫声
    print(w);        //狼的叫声

    return 0;
}

虚析构函数

在以后开发过程中,如果定义的类作为基类使用,那么要将其析构函数设置成虚析构函数
功能:争取指引 delete 关键字释放子类空间的
virtual ~Person () { cout << "Person::xigou" << endl ;}

抽象类:不能实例化对象,但是可以定义引用和指针

virtual void show () = 0 ; //纯虚函数, 在类中,只有声明,没有定义
类中包含至少一个纯虚函数,那么该类便是抽象类
#include <iostream>

using namespace std;

class Animal   //如果类中有纯虚函数,那么该类便是抽象类
                //抽象类不允许实例化对象,但是可以用抽象类的指针或引用
{
protected:
    string name;
    string food;      //食物
public:
    Animal() {cout<<"Animal::construct"<<endl;}
    Animal(string n, string f):name(n), food(f) {}

    virtual void voice() = 0;   //纯虚函数
                  //所在类,无需通过实例调用该函数,只是为了让子类进行重写的函数

};

class Sheep : public Animal
{
private:
    int leg;         //腿的个数

public:
    Sheep() {}
    Sheep(string n, string f, int l):Animal(n, f), leg(l) {}

    void voice() override
    {
        cout<<name<<"   "<<food<<"   "<<leg;
        cout<<"   mie mie mie..."<<endl;
    }
};

class Wolf : public Animal
{
private:
    int tail;         //尾巴的个数

public:
    Wolf() {}
    Wolf(string n, string f, int t):Animal(n, f), tail(t) {}

    void voice() override
    {
        cout<<name<<"   "<<food<<"   "<<tail;
        cout<<"   wu wuu wuuu..."<<endl;
    }
};


void print(Animal & a)
{
    a.voice();
}



int main()
{
    Sheep s("xiyy", "gress", 4);
    s.voice();

    Wolf w("xiaohh", "meat", 1);
    w.voice();

    cout<<"*******************************"<<endl;
    print(s);      //羊的叫声
    print(w);        //狼的叫声

    cout<<"*******************************"<<endl;
    //Animal a;        //报错,抽象类是不允许实例化对象的
    //a.voice();
    Animal &a=s;     //抽象类通过引用实例化对象
    a.voice();
    return 0;
}

函数模板

1> 有时程序员定义函数时,由于函数参数类型不同,或者参数的返回值类型不
同,会导致定义多个功能性质相同的函数,造成代码的冗余,此时我们可以考虑定义
函数模板来实现
2> 所谓函数模板,就是在定义函数时,函数参数和返回值的类型都不给定,而
是由函数调用时实参进行传递过来使用
3> 定义函数模板时跟普通函数有所区别,但是调用函数时,隐式调用跟普通函
数调用没有区别,系统会根据传递参数的类型,自动推导函数的类型。
4> 也可以进行显式调用,在调用函数名后加个尖括号,写上要传递的类型:尖
找尖,圆找圆
5> 一个模板只能对应下面一个函数,如果要再定义目标函数,需要重新定义模
板参数
/*
* template <typename T>
* template :定义模板的关键字,说明要开始定义模板了
* <>: 里面时类型形参名,里面可以有多个类型的参数,中间用逗号隔开
* template <typename T1 typename T2 ,。。。, Tn >
* typename: 声明类型的形参,也可以用关键字 class
* */
#include <iostream>

using namespace std;
//定义函数模板,参数和返回值的类型不给定
//而是有函数调用时,实参传递过来
template <typename T>
T my_sum(T m,T n)
{
    return m+n;
}
int main()
{
    cout << my_sum(1,2)<< endl;  //隐式调用,自动识别类型
    cout << my_sum<double>(1.5,2)<< endl;//显示调用,跟上类型名
    //c++返回值只输出有效数字,如 double (2 +3)=5
    cout<<"00000000"<<endl;
    cout << my_sum(1.2,2.1)<< endl;
   // "hi" 加string转成c++风格字符串 ;c风格是字符串类型
    cout << my_sum(string("hi "),string("hello"))<< endl;
    return 0;
}
T my_sum ( T m , int n ) // 函数模板的特化

模板类

template < typename T >
class Node
{
private :
T data ; // 数据域
Node * next ; // 指针域
public :
Node () {}
Node ( T d ): data ( d ), next ( NULL ) {}
void show ();
}
// 后面只要用到 Node ,就要加 <T>, 并且在前面要声明模板
template < typename T >
void Node < T > :: show ()
{
cout << data << endl ;
}
#include <iostream>

using namespace std;

template<typename T>
class Node
{
private:
    T data;       //数据域
    Node *next;       //指针域
public:
    Node() {}
    Node(T d):data(d), next(NULL) {}

    void show();

};

//后面只要用到Node,就要加<T>,并且在前面要声明模板
template<typename T>
void Node<T>::show()
{
    cout<<data<<endl;
}


int main()
{
    //必须显性调用
    Node<int> p1(10);    //10
    p1.show();

    Node<char> p2('a');  //a
    p2.show();

    Node<string> p3("hello");   //hello
    p3.show();

    return 0;
}
核心机制:延时编译、二次编译
当编译器第一次遇到函数模板或者类模板时,由于类型不明确,所以只是对除了类型之外的其他的相关语法的检查,如果检查无误,则会生产模板的内部实现机制。
当编译器第二次遇到函数模板或者类模板时,会根据传过来的实参的类型,确定模板类型,再一次进行语法检查,如果无误,则会生产函数或者类的原型。

STL标准模板库

C++ STL (Standard Template Library 标准模板库 ) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues ( 队列 ), lists ( 链表 ), stacks ( ) 等.
vector 函数运用
#include <iostream>
#include<vector>

using namespace std;

int main()
{
    vector<int> v1;        //无参构造一个vector对象

    //判断容器内是否为空
    if(v1.empty())
    {
        cout<<"empty"<<endl;
    }else
    {
        cout<<"not empty"<<endl;
    }

    //求容器大小
    cout<<"size of v1:"<<v1.size()<<endl;

    //求容器当前最大容量
    cout<<"capacity of v1:"<<v1.capacity()<<endl;

    //进行尾插
    for(int i=0; i<5; i++)
       {
           v1.push_back(i+10);
           cout<<"capacity of v1:"<<v1.capacity()<<endl;
       }
       cout<<"size of v1:"<<v1.size()<<endl;

       //尾删
       v1.pop_back();
       cout<<"size of v1:"<<v1.size()<<endl;

       for(int i=0; i<v1.size(); i++)
       {
           //cout<<v1.at(i)<<" ";
           cout<<v1[i]<<" ";
       }
       cout<<endl;
       //找到第一个和最后一个
          cout<<"the first one:"<<v1.front()<<endl;
          cout<<"the last one:"<<v1.back()<<endl;

          //使用迭代器遍历容器

          for( auto it=v1.begin(); it!=v1.end(); it++ )
          //for( vector<int>::iterator it=v1.begin(); it!=v1.end(); it++ )
          {
              cout<<*it<<" ";
          }
          cout<<endl;

          //使用枚举for循环输出容器信息
          for(int va:v1)
          {
              cout<<va<<" ";
          }
          cout<<endl;

          //清空所有元素
          v1.clear();
          cout<<"size of v1:"<<v1.size()<<endl;

       cout<<"***************************************"<<endl;
       int arr[10] = {2,3,6,8,4,5,1,9,37,7};
           vector<int> v3(arr, arr+6);
           //从数组开始到第6个位置,放到容器中
           for(auto val:v3)
           {
               cout<<val<<" ";

           }
           cout<<endl;
           return 0;
       }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值