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

2016-05-07  本文已影响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;
    }       
}
上一篇下一篇

猜你喜欢

热点阅读