美文网首页
(GeekBand)C++面向对象之无指针类

(GeekBand)C++面向对象之无指针类

作者: 东方未曦 | 来源:发表于2016-05-07 23:09 被阅读156次

    课堂笔记

    1.模板的定义及使用:

    有时候我们不确定要定义的类里面的数据类型,因此我们使用模板来定义这个数据。这样在类实例化的时候可以临时定义它的数据类型。
    使用模板T时要在开头加上一句声明。

    //定义一个类型名。
    Template<typename T>
    class complex
    {
    public:
        complex ( T r = 0, T i = 0 )
         : re( r ), im( i )
        { }
    private:
        T re, im;
    };
    //main函数部分;
    {
        //在这里可以为某个对象定义特定的数据类型;
        complex<double> c1( 1.5, 2.5 );
        complex<int> c2( 1, 2 );
    }
    

    2.inline函数

    定义:

    inline用来定义一个类的内联函数,引入它的主要原因是用它替代C中的宏定义。
    它消除了宏定义的缺点,同时又很好地继承了宏定义的优点。

    优点:

    1. C中使用define这种形式宏定义的原因是因为,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。
    2. 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。
    3. 在C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。

    3.构造函数放置于private区域

    用处:

    如果一个类的构造函数只有一个且是private,并且类的内部有专门创建实例的代码,则只能创建一个或多个实例(根据类内部声明的成员对象个数来定)。

    举例:

    class A
    {
    public:
        static A& getInstance( );
        setup( ) { ... }
    
    private:
        A( );
        A( const A& rhs );
    };
    
    A& A::getInstance( )
    {
        static A a;
        return a;
    }
    

    在使用的时候应使用如下代码:

    A::getInstance().setup();
    

    4.函数定义中的const:

    class complex
    {
    public:
        complex ( double r = 0, double i = 0 )
         : re( r ), im( i )
        { }
        //返回时加上const;
        double real() const { return re; }
        double imag() const { return im; }
    
    private:
        double re, im;
    };
    
    {
        //如果函数中不添加const,编译器会报错,因为这里已经将c1定义为const,
        //即c1不能改变,而函数中不添加const则代表数据可以被改变。
        const complex c1( 2, 1 );
        cout<<c1.real();
        cout<<c1.imag();
    }
    

    5.参数传递&运算符重载:

    传递参数一般使用引用传递(pass by reference)。
    因为类里的数据一般较为庞大,如果使用值传递会消耗较大的资源,而引用在底层就相当于指针,因此可以消耗少量资源进行参数的传递。

    举例:

    下面的代码重载了运算符 " += " ,如果它在类中进行声明,则它只需要一个参数,因为在类中本身自带 this 指针这个参数。
    complex&
    operator += ( const complex& r )
    {
        this->re += r.re;
        this->im += r.im;
        return *this;
    }
    
    下面的代码重载了运算符" + ",它使用了两个参数,并且最后返回了一个临时变量。
    inline complex
    operator + ( double x, const complex& y )
    {
        return complex ( x + real (y), imag (y) );
    }
    
    下面的代码重载了运算符" << ",使其输出时能直接使用cout。
    ostream&
    operator << ( ostream& , const complex& A )
    {
        return os <<' ( '<<real(x)<<' , '<<imag(x)<<' ) ';
    }
    
    当然也有情况不能使用引用传递。

    例如你需要在函数中创建一个临时变量来存储数据,当函数结束时,引用的对象实际上已经死亡,引用的东西就发生了错误。

    作业:

    要求:

    为Date类实现如下成员:
    1. 构造器,可以初始化年、月、日。
    2. 大于、小于、等于(> 、< 、==)操作符重载,进行日期比较。
    3. print() 打印出类似 2015-10-1 这样的格式。
    然后创建两个全局函数:
    1. 第1个函数 CreatePoints生成10个随机的Date,并以数组形式返回;
    2. 第2个函数 Sort 对第1个函数CreatePoints生成的结果,将其按照从小到大进行排序。
    main函数部分:

    最后在main函数中调用CreatePoints,并调用print将结果打印出来。然后调用Sort函数对前面结果处理后,并再次调用print将结果打印出来。

    代码:

    #ifndef DATE_H
    #define DATE_H
    
    #include <iostream>
    using namespace std;
    
    class Date
    {
        private:
            int year;
            int month;
            int day;
        
        public:
            //构造函数
            Date( int y = 0, int m = 0, int d = 0 ): year(y), month(m), day(d) { }
            
            //初始化函数
            void setYear( int y ) { year = y; }
            void setMonth( int m ) { month = m; }
            void setDay( int d ) { day = d; } 
            
            //获取私有成员
            int getYear() const { return year; }
            int getMonth() const { return month; }
            int getDay() const { return day; }
            
            //打印函数
                void print() { cout<<year<<'-'<<month<<'-'<<day<<endl; }
            
            //重载“ = ”的声明;
            inline Date& operator = ( const Date& x );
            
    };
    
    inline bool
    operator == ( const Date& x, const Date& y )
    {
        return ( x.getYear() == y.getYear() && x.getMonth() == y.getMonth() && x.getDay() && y.getDay() );
    }
    
    inline bool
    operator > ( const Date& x, const Date& y )
    {
        return ( x.getYear() > y.getYear()
                || x.getYear() == y.getYear() && x.getMonth() > y.getMonth()
                || x.getYear() == y.getYear() && x.getMonth() == y.getMonth() && x.getDay() > y.getDay() );
    }
    
    inline bool
    operator < ( const Date& x, const Date& y )
    {
        return ( x.getYear() < y.getYear()
                || x.getYear() == y.getYear() && x.getMonth() < y.getMonth()
                || x.getYear() == y.getYear() && x.getMonth() == y.getMonth() && x.getDay() < y.getDay() );
    }
    
    inline Date&
    Date::operator = ( const Date& x )
    {
        this->year = x.year;
        this->month = x.month;
        this->day = x.day;
        
        return *this;
    }
    
    #endif
    
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include "date.h"
    
    using namespace std;
    
    //宏定义random()函数; 
    #define random(x) ( rand() % x )
    
    Date* CreatePoints( int n );
    void Sort( Date test[], int n );
    
    int main(int argc, char** argv) {
        
        //打印未排序的日期序列; 
        Date* test = CreatePoints( 10 );
        cout<<"未排序的日期序列:"<<endl;
        for( int i = 0; i < 10; ++i ) test[i].print();
        
        //排序后再次打印该序列;
        Sort( test, 10 );
        cout<<"排序后的日期序列:"<<endl;
        for( int i = 0; i < 10; ++i ) test[i].print();
        
        return 0;
    }
    
    //随机生成10个日期; 
    Date* CreatePoints( int n )
    {
        //在这里new一个Date数组一直存放于内存中,最后把首地址传递出去;
        Date *test = new Date[n];
        
        //随机数种子; 
        srand( (int)time(0) );
        
        for( int i = 0; i < n; ++i )
        {
            test[i].setYear( random( 20 ) + 1990 );
            test[i].setMonth( random( 11 ) + 1 );
            
            //定义闰年以及平年每月的天数;
            int leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            int common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            
            //通过判断年份来确定该月的天数; 
            if( test[i].getYear() % 400 == 0 || test[i].getYear() % 4 == 0 && test[i].getYear() % 100 != 0 )
            {
                test[i].setDay( random( leap[test[i].getMonth()]-1 ) + 2 );
            }
            else
            {
                test[i].setDay( random( common[test[i].getMonth()]-1 ) + 2 );
            }
            
        }
        
        return test;
    }
    
    //对日期进行排序,这里使用的是选择排序;
    void Sort( Date test[], int n )
    {
        for( int i = 0; i < n; ++i )
        {
            Date min = test[i]; 
            Date temp;
            int index = i;
            for( int j = i+1; j < n; ++j)
            {
                if( test[j] < min)
                {
                    min = test[j]; 
                    index = j;
                }
            }
            temp = test[i];
            test[i] = min;
            test[index]= temp;
        }       
    }
    

    相关文章

      网友评论

          本文标题:(GeekBand)C++面向对象之无指针类

          本文链接:https://www.haomeiwen.com/subject/rkhsrttx.html