啃食c++(2)

泛型编程
独立于任何特定类型的方式编写代码。
类模板入门
类模板是c++泛性编程的基础,听了接近一个小时的讲课,只对老师的一句话印象比较深刻,不必造相同的轮子。恩,这句话已经概括了模板类的实质。
个人理解模板类就是我们在c++编程时,有些数据类型是不一样,但是在操作这些类型的数据是,总会存在一些交集操作。这时我们通过模板类将这些相同的操作加以实现,在定义时,将这种类型的的数据定义成一个集合,可执行模板类里已经存在的方法。
模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。
官方概念
人们需要编写多个形式和功能都相似的函数,因此有了函数模板来减少重复劳动;人们也需要编写多个形式和功能都相似的类,于是 C++ 引人了类模板的概念,编译器从类模板可以自动生成多个类,避免了程序员的重复劳动。
很明显,我的定义太过通俗!!!
定义模板类(使用模板类实现一个简单的堆栈)

#include<iostream>
using namespace std;
enum{SIZE = 100};
template <typename T>
class stack{
    
private:
    int top ;
    T data[SIZE] ;
public:
    stack():top(0){}
    ~stack(){}
    void push(T da){
        data[top] = da ;
        top++ ;
    }
    T pop(){
        top -- ;
        return data[top] ;
    }
    int getTop(){
        return top ;
    }
};

int main(){
//定义一个存有整型数int的栈模板,当然可以定义其他简单类型的模板类
//一个类模板,应用运算符重载来实现类的栈操作,这里整型数比较简单一点
    stack<int>a ;
    int i ;
    while(cin>>i){
        if(a.getTop()==SIZE||i==-1)break ;
        a.push(i);
    }
    while(a.getTop()!= 0){
        cout<<a.pop()<<endl;;
    }
}

多态
自己对于多态第一印象来源与java语言,在java语言中使用多态,就记住一点,出现基类的地方可以出现子类,基类可以通过引用子类的示例来实现调用父类中的特定方法满足不同子类执行属于他们的动作(java学的不是很好,总结的不到位,标准还是参考官方概念的好),总之多态的实现依赖与子类可以在任何情况下被其父类引用。c++里面的多态核心没变,和里面的语法略有出入。
多态就指多种行为
多态指多种行为,同样的方法调用而执行不同操作(支撑这一操作的基础就是父类因引用子类对象,因此这又是建立在继承基础上的操作),运行不同代码,多态通过分离做什么和怎么做,从另一个角度将接口和实现进行分离。

#include<iostream>
using namespace std;
class father{
public :
    father(){}
    //防止内存泄露,定义父类虚函数,在本程序中不能体现其作用
    //但要养成这种编程习惯
    virtual ~father(){}
    //要实现多态的方法
    virtual void print(){}
};
//子类继承父类
class son1:public father{
public:
    son1(){}
    ~son1(){}
    void print(){
        cout<<"the son1"<<endl ;
    }
};
class son2:public father{
public:
    son2(){};
    ~son2(){};
    void print(){
        cout<<"the son2"<<endl ;
    }
};
//父类通过外部函数引用子类,执行不同子类的同一种动作
void print(father &son){    
    son.print();
}
int main(){    
    son1 s1 ;
    son2 s2 ;
    print(s1);
    print(s2);
}

以上程序是一个多态的简单实现,通过父类引用子类执行不同子类的方法,为什么要为基类设置虚的析构函数呢?

#include<iostream>
using namespace std;
class father{
public :
    father(){

        cout<<"father construct "<<endl ;
    }
      ~father(){
        cout<<"father disconstruct"<<endl ;
    }
    virtual void print(){}
};
class son1:public father{
public:
    son1(){
        cout<<"son1 construct"<<endl ;
    }
    ~son1(){
        cout<<"son1 disconstruct"<<endl;
    }
    void print(){
        cout<<"the son1"<<endl ;
    }
};
class son2:public father{
public:
    son2(){
        cout<<"son2 constuct"<<endl ;
    }
    ~son2(){
        cout<<"son2 disconstruct"<<endl;
    }
    void print(){
        cout<<"the son2"<<endl ;
    }
};

void print(father *son){
    
    son->print();
}
int main(){
    
    father*s1 = new son1;
    father*s2 = new son2 ;
    print(s1);
    print(s2);
    delete s1;
    delete s2 ;
}

以下是上述代码运行截图

在这里插入图片描述
以下是加上给基类析构函数加上virtual的运行截图
在这里插入图片描述
以上很明显,要是不给基类的析构函数加virtual那么可能造成子类申请的内存不会被析构,导致内存泄露的风险。所以为了安全性,在任何时候都给将父类的析构函数设置为虚函数。

猜你喜欢

转载自blog.csdn.net/qq_41681241/article/details/83721946