GeekBand C++面向对象高级编程(上)(第一周):如何创建一个类

为Date类实现如下成员:

  1. 构造器,可以初始化年、月、日。
  2. 大于、小于、等于(> 、< 、==)操作符重载,进行日期比较。
  3. print() 打印出类似 2015-10-1 这样的格式。

基于上文的要求,创建一个Date类

1. 设计Date类

  • 首先,根据要求,设计三个私有成员变量:
    Demo_0
class Date
{
private:
    int year;
    int month;
    int day;
};
  • 根据上文给出的要求,还需要包含如下函数:
    Demo_1
Date();
Date(int _year = 1900, int _month = 1, int _day = 1) :
//访问私有成员变量,此处并非必要
inline int getYear()  const ;//常成员函数, 它不改变对象的成员变量
inline int getMonth() const ;
inline int getDay()   const ;
//重载操作符进行日期大小的比较
bool operator < (const Date & rhs)const;
inline bool operator == (const Date & rhs)const;
inline bool operator >(const Date & rhs)const;
//按格式打印日期
inline bool print();

2.类的实现

2.1构造函数##

2.1.构造函数的实现###

Demo_2

1 Date();
2 Date(int _year,int _month,int _day);

类在构造函数中进行数据成员的初始化,任何类的对象只要被创建,就会执行构造函数。
构造函数的名字和类名相同。构造函数没有返回类型,但是可以和其他函数一样有一个(也可能为空)的参数列表和一个(也可能为空)的函数体。形如上方第1行,第2行的代码。
此外,构造函数不能声明为const的,其实这也很好理解,声明为const的成员函数是不可以改变对象的成员变量的,更遑论初始化成员变量。

2.1.2构造函数的设计###

类可以有多个构造函数,上文中第1行,第2行的函数都是构造函数。第1行的构造函数对类的成员变量进行默认的初始化,第2行的构造函数可以根据传入的参数初始化成员变量。

2.1.3为什么要对构造函数进行设计?###

2.1.3.1合成默认构造函数####

  • 我们已经知道构造函数是对类的成员变量进行初始化,但是当我们编写一个类,却没有编写构造函数时,我们会发现成员变量已经被初始化(虽然初始化的值可能不那么可爱),这是因为这个时候类通过一个特殊的构造函数来控制默认初始化过程,这个函数称之为默认构造函数。默认构造函数无需任何参数(就是上文第1行的代码)。
  • 此时我们没有显式的定义构造函数或者默认构造函数,编译器就为我们隐式的创建了一个默认构造函数。这种编译器创建的构造函数又叫做合成的默认构造函数
     注:只有当类没有声明任何构造函数时,编译器才会自动生成默认构造函数。

2.1.3.2显示定义构造函数####

  • 上面说过,类没有声明任何构造函数时,编译器会自动生成默认构造函数。但是这种默认构造函数初始化的值不一定是我们想要的,甚至有可能是错误的(TODO),为了解决这个问题,我们需要显式的对类的成员变量进行正确的初始化。
  • 代码块第2行的代码就是这样的一个设计。我们根据实际的需要还可以进行类似的设计。但是为什么还要保留代码块第1行的构造函数呢?这不是必须的,但是是建议的。让我们来看看缺少默认构造函数会是个什么情况。
    Demo_3
  1  #include <iostream>
  2  class Test1
  3  {
  4  public:
  5     Test1(int _i)
  6     {
  7         i = _i;
  8         std::cout <<i<<std::endl;
  9     }
 10  private:
 11    int i;
 12 };
 13 int main(void)
 14 {
 15 //Test1 t1;
 16   Test1 t2(3);
 17   system("pause");
 18   return 0;
 19 }
  • 在Demo_3中,第15行被注释掉了,这是因为我们没有定义默认构造函数,编译器并不认识形如“Test1 tt;“的函数语句,只能使用第16行的方式,这样使用起来多有不便,所以建议显示定义个默认构造函数。
  • 显示定义的默认构造函数可以有两种选择:1是:
    Demo_4
 Test1() = default;     //C++11
 Test1() {}

上述两行的代码是一致的,会初始化成员变量,但初始值并不能尽如人意。
2是:
Demo_5

 Test1():_i(0){}      //使用初始化列表
 Test1(){_i = 0;}

上述两行代码同样完成了默认构造函数的初始化的设置,建议使用初始化列表。

那么言归正传,让我们回到Date类的设计上来,根据上面的阐述,我们应该有下面的代码:
Demo_6

  Date(){year = 1900;month = 1;day =1;}
  Date(int _year,int _month,int _day):
   year(_year),month(_month),day(_day)
  {}

2.1.3.3构造函数的默实参####

其实我们还有一个更好的选择,那就是为自定义的构造函数设置默认实参
Demo_7

Date(int _year =1900 , int _month = 1, int _day =1) :
        year(_year), month(_month), day(_day)
    {}

我们使用下面的方法来实例化一个Date类,都是正确的:
Demo_8

Date date1();                  //1900-1-1
Date date(2012);               //2012-1-1
Date date(2013,2);             //2013-2-1
Date date(2014,3,3);           //2014-3-3

2.2操作符重载##

2.2.1成员函数的操作符重载###

Demo_9

//重载操作符进行日期大小的比较
bool operator < (const Date & rhs)const;
inline bool operator == (const Date & rhs)const;
inline bool operator >(const Date & rhs)const;

关于成员函数的操作符重载,只有一点需要说明,那就是:

相同class的各个objects互为友元

让我们截取“<”重载的一段代码来说明下这是什么意思:
Demo_10

bool Date::operator < (const Date & rhs)const
{
//  if (this->getYear() < rhs.getYear())
      if(this.year <rhs.year)
      {
        return true;
    }
    ......
    ......
}

由于Date类中year,month,day是私有的,所以通常来说,Demo_10中的rhs是不能够直接使用rhs.year 来进行比较的,但是根据刚刚我们了解到的“相同class的各个objects互为友元”的规则来看,它确实是可行的。

2.2.2非成员函数的操作符重载###

  • 其实Demo_9中的三个操作符也可以用非成员函数的形式进行重载,一般来说,可以有友元函数和全局函数两种,只是全局函数的实现有时候依赖于类是否设计了获取修改类私有成员变量,毕竟全局函数没有访问类的私有成员的权限。
  • 所以一般也可以写成友元函数的形式。友元类或者友元函数可以访问类的非公有成员。方便了使用,却破坏了封装性。
  • 下面是友元函数形式的重载:
    Demo_11
//重载操作符进行日期大小的比较
friend bool operator < (const Date & this,const Date & rhs)const;
friend bool operator == (const Date & this,const Date & rhs)const;
friend bool operator >(const Date & this,const Date & rhs)const;

2.2.3不可以使用成员函数的操作符重载###

这里说的是“<<”和“>>”操作符
试想一下,根据之前成员函数的重载规则,我们将输出到std::cout的代码写成如下形式:
Demo_12

  Date myDate;
  myDate << std::cout;

这种形式,实在是不符合我们的认知。
我们要实现格式打印功能,需要对输出操作符重载。有两个选择,全局函数或者友元函数,都可以,略。

至此,Date类基本要求完成。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容