zoukankan      html  css  js  c++  java
  • C++ —— 类模板的分离式编译

    目录
    1. 对于C++中类模板的分离式编译的认识
    2. 具体的实例
    1、对于C++中类模板的分离式编译的认识
    为什么C++编译器不能支持对模板的分离式编译(博文链接)

    主要内容:编译器编译的一般工作原理、对模版的分离式编译的特殊性(模版的特殊性)

    链接:  http://blog.csdn.net/pongba/article/details/19130

    模版编译的特殊性

      对程序进行编译时,对于函数调用,编译器只要求函数的原型在调用点是可见的,至于函数的定义是否存在不做检查(在对程序进行链接时才检查函数的定义)。类似的,对于对象声明,编译器只要求所属的类定义在声明点是可见的,至于各成员函数的定义是否存在则不进行检查。因此,为了提高程序的可读性和可维护性,我们通常将函数原型和类定义放在头文件(.h文件)中,而函数定义(包括类成员函数的定义)则放在源文件(.cpp文件,又称实现文件)中。

      但是,模版编译则有所不同。从本质上说,模版并不是代码,而是指导编译器生成代码的指令,模版实例才是真正的程序代码。编译器看到模版定义的时候,不会立刻产生代码,只有在看到模版的使用(如调用函数模版、使用类模版定义对象或通过对象调用类模板的成员函数)时,才会进行实例化,使用特定的模版实例代码。而为了成功地进行实例化,编译器必须能够使用相应的函数定义,因此,模版编译要求模版的定义和实现采用特别的文件组织方式。

      C++语言中定义了两种编译模式:包含编译模式(inclusion compilation model)和 分离编译模式(separate compilation model)。

      ......

        ——摘自《C++语言程序设计》(蒋爱军、刘红梅、王勇、梁小萍编著)P349 13.3.3 模版编译与类模板的实现

      ......

      提示:分离编译模式实现起来比较困难,因此,所有的C++编译器都支持包含编译模式,而只有某些C++编译器支持分离编模式。程序员在编译使用自定义的模版的程序时,需要查阅编译器的用户指南,以确定自己所用的编译器支持那种编译模式。

        ——摘自《C++语言程序设计》(蒋爱军、刘红梅、王勇、梁小萍编著)P352 13.3.3 分离编译模式


    2、具体的实例

      在此演示一般的编译实例,和对于 函数或类模版的编译实例。

    (1)一般的编译

       以自定义类date为例,首先创建一个Console Application project工程文件(选用C++实现),向其中添加  date.h 和 date.cpp 两个文件,其中,date.h 存放 类的声明,而 date.cpp 对 date.h 中声明的类中的函数做具体的函数定义(函数实现)。

      ①date.h仅需要存放对类的声明就好。

    //**********************************************************************************
    //Date.h
    //对类Date及其派生类Ndate 进行声明
    //**********************************************************************************
    class Date
    {
    public:
        Date(int initYear=2014, int initMonth=1, int initDay=1);
        void set(int nYear,int nMonth, int nDay);
        int getYear()const;
        int getMonth()const;
        int getDay()const;
        void print()const;
        void increment();
        void decrement();
    
    private:
        int month;
        int year;
        int day;
    };
    
    class Ndate: public Date
    {
    public:
        Ndate(int initYear=2014, int initMonth=10, int initDay=16);
        void n_increment(int n);
        void n_decrement(int n);
    };
    View Code

      ②date.cpp 需要 include"date.h" 然后再对 date.h 中声明的类中的函数做具体的函数定义。(注意:实现文件包含头文件)

    //**********************************************************************************
    //Date.cpp
    //对Date.h 中声明的函数进行定义
    //**********************************************************************************
    #include "date.h"
    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    int daysInMonth(int mo,int yr);
    
    Date::Date(int initYear, int initMonth, int initDay)
    {
        year=initYear;
        month=initMonth;
        day=initDay;
    }
    void Date::set( int nYear,int nMonth, int nDay)
    {
        year=nYear;
        month=nMonth;
        day=nDay;
    }
    
    int Date::getYear()const
    {
        return year;
    }
    int Date::getMonth()const
    {
        return month;
    }
    int Date::getDay()const
    {
        return day;
    }
    void Date::print()const
    {
        switch(month)
        {
        case 1:
            cout<<setw(9)<< "January"<<setw(3);
            break;
        case 2:
            cout<<setw(9)<< "Fabruary"<<setw(3);
            break;
        case 3:
            cout<<setw(9)<< "March"<<setw(3);
            break;
        case 4:
            cout<<setw(9)<< "April"<<setw(3);
            break;
        case 5:
            cout<<setw(9)<< "May"<<setw(3);
            break;
        case 6:
            cout<<setw(9)<< "June"<<setw(3);
            break;
        case 7:
            cout<<setw(9)<< "July"<<setw(3);
            break;
        case 8:
            cout<<setw(9)<< "August"<<setw(3);
            break;
        case 9:
            cout<<setw(9)<< "September"<<setw(3);
            break;
        case 10:
            cout<<setw(9)<< "October"<<setw(3);
            break;
        case 11:
            cout<<setw(9)<< "November"<<setw(3);
            break;
        case 12:
            cout<<setw(9)<< "December"<<setw(3);
            break;
        }
        cout<< day << setw(5)<<year<< endl;
    }
    
    void Date::increment()
    {
        day++;
        if(day > daysInMonth(month,year))
        {
            day=1;
            month++;
            if( month>12)
            {
                month=1;
                year++;
            }
        }
    }
    void Date::decrement()
    {
        day--;
        if(day==0)
        {
            if(month==1)
            {
                day=31;
                month=12;
                year--;
            }
            else
            {
                month--;
                day= daysInMonth(month, year);
            }
        }
    }
    int daysInMonth(int mo,int yr)
    {
        switch (mo)
        {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            return 31;
        case 4:
        case 6:
        case 9:
        case 11:
            return 30;
        case 2:
            if((yr % 4== 0&&yr %100 !=0)||yr % 400 == 0)
                return 29;
            else
                return 28;
        }
    }
    Ndate::Ndate(int initYear, int initMonth, int initDay)
    {
        set(initYear,initMonth,initDay);
    }
    void Ndate::n_increment(int n)
    {
        for(int i=1; i<=n; i++)
            increment();
    }
    void Ndate::n_decrement(int n)
    {
        for(int i=1; i<=n; i++)
            decrement();
    }
    View Code

      ③以创建project后自动生成的main.cpp 中的 main() 作为程序执行入口,使用date的派生类Ndate 的实例化对象。需要 include"date.h"。

    //**********************************************************************************
    //main.cpp
    //实例化 date 并使用
    //**********************************************************************************
    
    #include <iostream>
    #include "date.h"
    
    using namespace std;
    
    int main()
    {
        Ndate date1(2008,8,8);           //1970,1,1 --> 14099 days -->2008,8,8
    
        for(int i=1; i<=16360-14099; i++)//1970,1,1 --> 16360 days -->2014,10,17
        {
            date1.increment();
        }
        date1.print();
    
        return 0;
    }
    View Code
    (2)对于 函数或类 模板的编译

      以定义函数模版M_swap为例(交换两个实参的值),首先创建一个Console Application project工程文件(选用C++实现),向其中添加 M_swap.h 和 M_swap.cpp 两个文件,其中,M_swap.h 存放 函数模版或类模版成员函数 的声明,而 M_swap.cpp 对 M_swap.h 中声明的 函数模版或类模版成员函数 做具体的定义(实现)。

      ①在M_swap.h存放对 函数模版或类模板成员函数 的声明及定义,或给出声明后用预处理指令#include包含实现文件。(注意:头文件中给出声明和定义 或  头文件包含实现文件)

    //**********************************************************************************
    //M_swap.h
    //存放对 函数模版或类模版成员函数 的声明及定义
    //**********************************************************************************
    #ifndef M_SWAP_H_INCLUDED
    #define M_SWAP_H_INCLUDED   //M_SWAP_H_INCLUDED为头文件相应的头文件哨兵
                                //当一个程序中因多次使用到模版时 而多次包含头文件M_swap.h时
                                //有可能出现“重复定义”的错误  因此使用#ifndef 语句
    template<class T>
    void M_swap(T &a,T &b);
                           //为了成功地对模版进行实例化,编译器必须能够使用相应的函数定义
                           //故 需要在头文件中直接给出函数的具体定义  但这样一般会导致头文件
                           //较长,而且模版的定义和实现混合在一起,不利于维护
    
                           //可用另一种办法,那便是
    #include "M_swap.cpp"
                           //在头文件中用预处理指令#include包含实现文件
    
    
    #endif // M_SWAP_H_INCLUDED
    View Code

      ②M_swap.cpp 直接给出 声明的 函数模版或类模版成员函数 做具体的函数定义。

    //**********************************************************************************
    //M_swap.cpp
    //给出 声明的 函数模版或类模版的成员函数 做具体的函数定义
    //**********************************************************************************
    #include <iostream>
    using namespace std;
    
    template<class T>
    void M_swap(T &a,T &b)
    {
        T temp;
    
        temp=a;
        a=b;
        b=temp;
        cout<<"swap completed!>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"<<endl;
    }
    View Code

      ③以创建project后自动生成的main.cpp 中的 main() 作为程序执行入口。实例化M_swap,需要 include"M_swap.h"。

    //**********************************************************************************
    //main.cpp
    //实例化 模版函数 M_swap 并交换两个实参的值
    //**********************************************************************************
    #include <iostream>
    #include <string>
    #include "M_swap.h"
    using namespace std;
    class Box{
        public:
            Box(double wi=1,double le=1,double he=1):w(wi),l(le),h(he)
            {cout<<"Box Constructor!
    ";}
            ~Box()
            {cout<<"Destrctor of Box!
    ";}
            double getWidth() const{return w;}
            double getLength()const{return l;}
            double getHeight()const{return h;}
            double getVolume()const{return w*l*h;}
            void setWidht(int wi) {w=wi;}
            void setLenght(int le){l=le;}
            void setHeight(int he){h=he;}
    
        private:
            double w;
            double l;
            double h;
    };
    int main()
    {
        int    i[2]={22 ,66 };
        char   c[2]={'a','b'};
        string s[2]={string(7,'n'),string(6,'v')};
        Box    b[2]={Box(12,12,12),Box(2,2,2)};
    
        cout<<"--------------------------------------
    ";
        cout<<"First:	"<<i[0]<<"	Second:	"<<i[1]<<endl;
        cout<<"First:	"<<c[0]<<"	Second:	"<<c[1]<<endl;
        cout<<"First:	"<<s[0]<<"	Second:	"<<s[1]<<endl;
        cout<<"First:	"<<b[0].getVolume()<<"	Second:	"<<b[1].getVolume()<<endl<<endl;
        cout<<"--------------------------------------
    ";
        M_swap(i[0],i[1]);
        M_swap(c[0],c[1]);
        M_swap(s[0],s[1]);
        M_swap(b[0],b[1]);
        cout<<"--------------------------------------
    ";
        cout<<"First:	"<<i[0]<<"	Second:	"<<i[1]<<endl;
        cout<<"First:	"<<c[0]<<"	Second:	"<<c[1]<<endl;
        cout<<"First:	"<<s[0]<<"	Second:	"<<s[1]<<endl;
        cout<<"First:	"<<b[0].getVolume()<<"	Second:	"<<b[1].getVolume()<<endl<<endl;
        cout<<"--------------------------------------
    ";
    
        return 0;
    }
    View Code

    版权声明
    本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者 BensonLaur  和本文原始地址:
  • 相关阅读:
    windows服务器性能监控工具、方法及关键指标
    js加密的密文让PHP解密(AES算法)
    在CentOS上搭建PHP服务器环境
    开发php的扩展模块(centos环境下)
    年终培训关于磁盘冗余阵列、热备、群集、负载均衡、云计算、F5、Nginx等的概念和基本原理
    5分钟开发一个简单的基于HTML5的移动应用
    【JAVA WEB教程】jsp环境搭建+部署网站(eclipse+tomcat)【详细+图文】
    linux图形化客户端
    【JAVA WEB教程】jsp环境搭建(eclipse)【详细+图文】
    如何预估服务器带宽需求【转】
  • 原文地址:https://www.cnblogs.com/BensonLaur/p/4322203.html
Copyright © 2011-2022 走看看