(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中的宏定义。
它消除了宏定义的缺点,同时又很好地继承了宏定义的优点。
优点:
- C中使用define这种形式宏定义的原因是因为,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。
- 这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。
- 在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类实现如下成员:
- 构造器,可以初始化年、月、日。
- 大于、小于、等于(> 、< 、==)操作符重载,进行日期比较。
- print() 打印出类似 2015-10-1 这样的格式。
然后创建两个全局函数:
- 第1个函数 CreatePoints生成10个随机的Date,并以数组形式返回;
- 第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;
}
}