# C++Primer学习笔记之第七章

第七章 类 __C++Primer第五版

类.png

定义抽象数据类型

7.1 练习

#include <iostream>
#include <string>
using namespace std;

//struct 和 class 的唯一区别是默认的访问权限。
//struct默认是public
//class默认是private

struct Sales_data
{
    string bookNo; //编号
    unsigned units_sold = 0; //卖出的数量, 类初始化,C++新标准,vs2010不支持
    double revenue = 0; //总金额
};

int main()
{
    Sales_data total;
    if (cin >> total.bookNo >> total.units_sold >> total.revenue)
    {
        Sales_data trans;
        while(cin >> trans.bookNo >> trans.units_sold >> trans.revenue)
        {
            if (trans.bookNo == total.bookNo)
            {
                total.units_sold += trans.units_sold;
                total.revenue += trans.revenue;
            }
            else
            {
                cout << total.bookNo << "\t" << total.units_sold << "\t" << total.revenue << endl;
                total = trans;
            }
        }
        cout << total.bookNo << "\t" << total.units_sold << "\t" << total.revenue << endl;
    }
    else
    {
        cerr << "No data?" << endl;
        return -1; //表示失败

    }

    return 0;
}

定义改进的Sales_data类

#ifndef SALES_DATA_H
#define SALES_DATA_H

#include <iostream>
#include <string>

struct Sales_data 
{
    //成员函数
    //获得isbn编号
    std::string isbn() const //const成员函数
    {
        return this->bookNo;
    }

    Sales_data& combine(const Sales_data&);

    double avg_price() const; //const成员函数


    //数据成员
    std::string bookNo;
    unsigned units_sole;
    double revenue;
};

//非成员函数
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream& print(std::ostream&, const Sales_data&);
std::istream& read(std::istream&, Sales_data&);

//对未定义的成员函数在类外进行定义
double Sales_data::avg_price() const
{
    if (units_sold)
    {
        return revenue/units_sold;
    }
    else
    {
        return 0;
    }
}

//定义一个返回this对象的函数
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
    this->units_sold += rhs.units_sold;
    this->revenue += rhs.revenue;
    return *this; //返回调用该函数的对象
}

//对非成员函数定义
std::istream& read(std::istream &is, Sales_data &item)
{
    double price = 0;
    //输入isbn编号, 卖出数量, 单价
    is >> item.bookNo >> item.units_sold >> price; 
    item.revenue = item.units_sold * price;
    return is;
}
std::ostream& print(std::ostream &os, const Sales_data &item)
{
    os << item.isbn() << "  " << item.units_sold << "  " 
        << item.revenue << "  " << item.avg_price();
    return os;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    //把lhs的数据成员拷贝给sum
    //默认情况下,拷贝类的对象其实拷贝的是对象的数据成员
    Sales_data sum = lhs; 
    sum.combine(rhs);
    return sum;
}
#endif

引入const成员函数

上面Sales_data类中的isbn()avg_price()函数都是常量成员函数。紧跟在参数列表后面的const表示this是一个指向常量的常量指针也就是const Sales_data const *类型,如果没有列表后面的const,this的类型是Sales_data const *类型。

常量对象以及常量对象的引用或指针都只能调用常量成员函数。

7.3 7.7练习题

#include <iostream>
#include <string>
#include "Sales_data.h"
using namespace std;

int main()
{
    Sales_data total;
    if (read(cin, total))
    {
        Sales_data trans;
        while(read(cin, trans))
        {
            if (trans.isbn() == total.isbn())
            {
                total.combine(trans);
            }
            else
            {
                print(cout, total);
                total = trans;
            }
        }
        print(cout, total);
    }
    else 
    {
        cout << "No Data?" << endl;
        return -1;
    }
    return 0;
}

7.4 7.5 7.9练习

编写一个名为Person的类,使其表示人员的姓名和住址。使用string对象存放这些元素,接下来的练习将不断充实这个类的其他特征。

#ifndef PERSON_H
#define PERSON_H

#include <iostream>
#include <string>

struct Person
{
    //数据成员
    std::string name;
    std::string address;

    //成员函数
    //返回name
    std::string getName() const
    {
        return this->name;
    }
    //返回address
    std::string getAddress() const{
        return this->address;
    }
};

std::ostream& print(std::ostream &os, const Person &p)
{
    os << p.getName() << "的地址是" << person.getAddress() << endl;
    return os;
}

std::istream& read(std::istream &is, Person &p)
{
    is >> p.name >> p.address;
    return is;
}

#endif
//练习7.5的 main.cpp
#include <iostream>
#include <string>
#include "Person.h"
using namespace std;

int main()
{
    Person person;
    //person.name = "MangoLee";
    //person.address = "Beijing";

    cin >> person.name >> person.address;

    cout << person.getName() << "的地址是" << person.getAddress() << endl;

    system("pause");
    return 0;
}

//练习7.9的main.cpp
int main()
{
    Person person;

    read(cin, person);
    print(cout, person);

    system("pause");
    return 0;
}

构造函数

默认构造函数

默认构造函数按照如下规则初始化类的数据成员:

  • 如果存在类内的初始值,用它来初始化成员(C++11)

  • struct Person
    {
      string name = 'mango';  //类内初始化,vs2010不支持此C++11新特性
          int age = 26; //类内初始化,vs2010不支持此C++11新特性
    }
    
  • 否则,默认初始化该成员

    • 如果是内置类型,定义于任何函数体之外的变量被初始化为0;定义在函数体内部的不被初始化
    • 每个类调用默认初始化

7.11-1.13 练习

为Sales_data添加构造函数,并用istream构造函数重写229页程序。

#ifndef SALES_DATA_H
#define SALES_DATA_H

#include <iostream>
#include <string>

struct Sales_data 
{
    //构造函数
    Sales_data();
    Sales_data(const std::string &str):
        bookNo(str),units_sold(0),revenue(0){}
    //初始化列表
    Sales_data(const std::string &str, unsigned n, double p):
        bookNo(str),units_sold(n),revenue(p){}
    Sales_data(std::istream &is);
  
    //成员函数
    //获得isbn编号
    std::string isbn() const
    {
        return this->bookNo;
    }
    Sales_data& combine(const Sales_data&);
    double avg_price() const;

    //数据成员
    std::string bookNo;
    unsigned units_sold;
    double revenue;
};

//非成员函数声明
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream& print(std::ostream&, const Sales_data&);
std::istream& read(std::istream&, Sales_data&);

Sales_data::Sales_data(std::istream &is)
{
    read(is, *this); //*this 代表本身
}

//对未定义的成员函数在类外进行定义
double Sales_data::avg_price() const
{
    if (units_sold)
    {
        return revenue/units_sold;
    }
    else
    {
        return 0;
    }
}

//定义一个返回this对象的函数
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
    this->units_sold += rhs.units_sold;
    this->revenue += rhs.revenue;
    return *this; //返回调用该函数的对象
}

//对非成员函数定义
std::istream& read(std::istream &is, Sales_data &item)
{
    double price = 0;
    //输入isbn编号, 卖出数量, 单价
    is >> item.bookNo >> item.units_sold >> price; 
    item.revenue = item.units_sold * price;
    return is;
}
std::ostream& print(std::ostream &os, const Sales_data &item)
{
    os << item.isbn() << "  " << item.units_sold << "  " 
        << item.revenue << "  " << item.avg_price();
    return os;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    //把lhs的数据成员拷贝给sum
    //默认情况下,拷贝类的对象其实拷贝的是对象的数据成员
    Sales_data sum = lhs; 
    sum.combine(rhs);
    return sum;
}
#endif

访问控制和封装

引入public 和private的关键词。

//Sales.data.h添加访问控制,函数实现不变。
class Sales_data 
{
public:
    Sales_data();
    Sales_data(const std::string &str):
        bookNo(str),units_sold(0),revenue(0){}
    Sales_data(const std::string &str, unsigned n, double p):
        bookNo(str),units_sold(n),revenue(p){}
    Sales_data(std::istream &is);
    std::string isbn() const{return this->bookNo;}
    Sales_data& combine(const Sales_data&);
private:
    double avg_price() const;
    std::string bookNo;
    unsigned units_sold;
    double revenue;
};

友元

类可以允许友元类和友元函数访问它的私有成员。

//Sales.data.h添加友元函数
class Sales_data 
{
  //友元声明,不代表普通声明,函数需要声明仍需要在类外进行声明
    friend Sales_data add(const Sales_data&, const Sales_data&);
    friend std::ostream& print(std::ostream&, const Sales_data&);
    friend std::istream& read(std::istream&, Sales_data&);
  
public:
    Sales_data();
    Sales_data(const std::string &str):
        bookNo(str),units_sold(0),revenue(0){}
    Sales_data(const std::string &str, unsigned n, double p):
        bookNo(str),units_sold(n),revenue(p){}
    Sales_data(std::istream &is);
    std::string isbn() const{return this->bookNo;}
    Sales_data& combine(const Sales_data&);
private:
    double avg_price() const;
    std::string bookNo;
    unsigned units_sold;
    double revenue;
};
//非成员函数声明
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream& print(std::ostream&, const Sales_data&);
std::istream& read(std::istream&, Sales_data&);

7.22 练习

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

推荐阅读更多精彩内容