跳到主内容

第一章:开始 | C++ Primer 5

main 函数

操作系统运行一个程序需要找到一个入口,main 函数就是 C++ 程序的入口。

int main(int argc, char* argv[]) {
    return 0;
}
param int argc

从命令行传入参数的数目;

param (char*)[] argv

从命令行传入的参数组成的数组,C-style 字符串;

return int

返回值作为程序的退出状态,约定 0 表示正常,其他值表示出现错误。

iostream

iostream 库提供了输入输出能力,包含两个类 istream, ostream。 其中, i 表示 in,所以是读;o 表示 out, 是写。

iostream 提供的读写功能以 的形式提供,「流」表示读写是顺序生成或消耗的。

提供了四个标准读写对象:

cin

标准输入

cout

标准输出

cerr

标准错误输出

clog

标准日志输出

从 C++ 程序到操作系统,c* 等标准输入输出可能会映射为不同的文件、缓冲区等, 通常来说,默认配置下的程序,其标准输入输出都连接至控制台。

c* 使用 <<>> 两个运算符,前者表示将某个东西送入 c*,后者表示从 c* 抽出:

// 导入符号,这样编译器才能在标准库中找到对应的对象
#include<iostream>
int main() { // 不需要命令行参数,可以省略掉 main 的形式参数
    // 标准库中的符号在 std 命名空间下,这里的声明让编译器知道后面的符号到 std:: 下去找
    using namespace std;
    int a = 0;
    int b = 0;
    // 从 stdin 读取一个数到 a
    cin >> a;
    // 从 stdin 读取一个数到 b
    cin >> b;
    // 向 stdout 输出
    cout << a << " + " << b << " = " << a + b << endl;
    return 0;
}

endlend line 的缩写,其作用就是终止当前行并且刷新缓冲区,根据输入模式的不同,可能会插入换行符。

测试 cout, cerr, clog 的关系:

#include <iostream>
int main() {
    using namespace std;
    cout << "cout" << endl;
    cerr << "cerr" << endl;
    clog << "clog" << endl;
}

利用操作系统文件描述符重定向的功能,将输入划分到不同的文件:

./a.out 1>cout.txt 2>cerr.txt 3>clog.txt

cout 的文件描述符是 1,cerr 和 clog 的文件描述符都是 2 。

注解

形式参数和实际参数

形式参数指在函数定义时写在后面的参数,其作用是表示一个符号、一个名字。 实际参数则是传递给函数的实际的值。

:: 是作用域运算符,作用是解开一层命名空间。C++ 中的命名空间设定是为了避免名字冲突。 如果没有命名空间则为了编译链接时,不将错误的代码链接到重复的符号上,就必须写很长的,不重复的名字。像 C 和 Object-C 一样。

控制流

while

先判定,再执行。

while(x < 100) {
    x += 1;
}

for

for(int i = 0; i < 100; i++) {
    x += i;
}

cin 的布尔值

int sum = 0;
int val = 0;
while(cin >> val) {
    sum += val;
}
cout << "= " << sum << endl;

cin 读取时会自动根据变量的类型解析输入,当能够成功解析时(在本例为字符串),其布尔值相当于 true;否则为 false。空白字符(空格、制表符、换行符等)将被忽略。

因此上面这个程序在遇到非整数字面量形式的输入时,循环将会结束,输出结果。

if

if( cond ) {

} else if ( cond ) {

} else {

}

类简介:SalesItem

书店程序,SalesItem 代表一个出版物的销售情况。

对于类,在设计时思考它有哪些性质,能执行哪些行为:

记录ISBN 书号

添加一个 isbn_id 的字段;

记录销售额、销量

添加对应字段来存储数据;

通过 iostream 读写

重载 <<>> 运算符;

复制 SalesItem 实例

使用 = 赋值号;

合并两条销售记录

重载 ++= 运算符; 并且,需要保证只有相同的商品(ISBN相同)的销售记录可以合并。

练习题

练习 1.6

下面这段程序不合法:

std::cout << "Hello World" << v1;
    << " and " << v2;
    << " is " << v1 + v2 << std::end;

因为分号结束语句,上面后两行的 << 运算符没有操作数。

更正:

- std::cout << "Hello World" << v1;
+ std::cout << "Hello World" << v1
-     << " and " << v2;
+     << " and " << v2

练习 1.20

cpp5/ch1/1-20.cc (源文件)

#include "SalesItem.h"

int main() {
  using namespace std;

  SalesItem si;
  while (cin >> si) {
    cout << si << endl;
  }
  return 0;
}

练习 1.21

cpp5/ch1/1-21.cc (源文件)

#include "SalesItem.h"

int main() {
  SalesItem a, b;
  std::cin >> a;
  std::cin >> b;
  if( a.isbn() == b.isbn()) {
    std::cout << a + b << std::endl;
  } else {
    std::cerr << "期望相同的 ISBN: " << a.isbn() << " != " << b.isbn() <<std::endl;
    return -1;
  }
  return 0;
}

练习 1.22

cpp5/ch1/1-22.cc (源文件)

#include "SalesItem.h"

int main() {
  SalesItem sum;
  std::cin >> sum;
  SalesItem cur;
  while (std::cin >> cur) {
    if (cur.isbn() == sum.isbn()) {
      sum += cur;
    } else {
      std::cerr << "期望相同的 ISBN:" << cur.isbn() << " != " << sum.isbn()
                << std::endl;
      return -1;
    }
  }
  std::cout << sum << std::endl;
  return 0;
}

参考

cpp5/ch1/SalesItem.h (源文件)

/*
 * This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
 * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
 * copyright and warranty notices given in that book:
 *
 * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
 *
 *
 * "The authors and publisher have taken care in the preparation of this book,
 * but make no expressed or implied warranty of any kind and assume no
 * responsibility for errors or omissions. No liability is assumed for
 * incidental or consequential damages in connection with or arising out of the
 * use of the information or programs contained herein."
 *
 * Permission is granted for this code to be used for educational purposes in
 * association with the book, given proper citation if and when posted or
 * reproduced.Any commercial use of this code requires the explicit written
 * permission of the publisher, Addison-Wesley Professional, a division of
 * Pearson Education, Inc. Send your request for permission, stating clearly
 * what code you would like to use, and in what specific way, to the following
 * address:
 *
 *     Pearson Education, Inc.
 *     Rights and Permissions Department
 *     One Lake Street
 *     Upper Saddle River, NJ  07458
 *     Fax: (201) 236-3290
 */

/* This file defines the SalesItem class used in chapter 1.
 * The code used in this file will be explained in
 * Chapter 7 (Classes) and Chapter 14 (Overloaded Operators)
 * Readers shouldn't try to understand the code in this file
 * until they have read those chapters.
 */

#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H

// Definition of SalesItem class and related functions goes here
#include <iostream>
#include <string>

class SalesItem {
  // these declarations are explained section 7.2.1, p. 270
  // and in chapter 14, pages 557, 558, 561
  friend std::istream &operator>>(std::istream &, SalesItem &);
  friend std::ostream &operator<<(std::ostream &, const SalesItem &);
  friend bool operator<(const SalesItem &, const SalesItem &);
  friend bool operator==(const SalesItem &, const SalesItem &);

public:
  // constructors are explained in section 7.1.4, pages 262 - 265
  // default constructor needed to initialize members of built-in type
  SalesItem() : units_sold(0), revenue(0.0) {}
  SalesItem(const std::string &book)
      : bookNo(book), units_sold(0), revenue(0.0) {}
  SalesItem(std::istream &is) { is >> *this; }

public:
  // operations on SalesItem objects
  // member binary operator: left-hand operand bound to implicit this pointer
  SalesItem &operator+=(const SalesItem &);

  // operations on SalesItem objects
  std::string isbn() const { return bookNo; }
  double avg_price() const;
  // private members as before
private:
  std::string bookNo; // implicitly initialized to the empty string
  unsigned units_sold;
  double revenue;
};

// used in chapter 10
inline bool compareIsbn(const SalesItem &lhs, const SalesItem &rhs) {
  return lhs.isbn() == rhs.isbn();
}

// nonmember binary operator: must declare a parameter for each operand
SalesItem operator+(const SalesItem &, const SalesItem &);

inline bool operator==(const SalesItem &lhs, const SalesItem &rhs) {
  // must be made a friend of SalesItem
  return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue &&
         lhs.isbn() == rhs.isbn();
}

inline bool operator!=(const SalesItem &lhs, const SalesItem &rhs) {
  return !(lhs == rhs); // != defined in terms of operator==
}

// assumes that both objects refer to the same ISBN
SalesItem &SalesItem::operator+=(const SalesItem &rhs) {
  units_sold += rhs.units_sold;
  revenue += rhs.revenue;
  return *this;
}

// assumes that both objects refer to the same ISBN
SalesItem operator+(const SalesItem &lhs, const SalesItem &rhs) {
  SalesItem ret(lhs); // copy (|lhs|) into a local object that we'll return
  ret += rhs;         // add in the contents of (|rhs|)
  return ret;         // return (|ret|) by value
}

std::istream &operator>>(std::istream &in, SalesItem &s) {
  double price;
  in >> s.bookNo >> s.units_sold >> price;
  // check that the inputs succeeded
  if (in)
    s.revenue = s.units_sold * price;
  else
    s = SalesItem(); // input failed: reset object to default state
  return in;
}

std::ostream &operator<<(std::ostream &out, const SalesItem &s) {
  out << s.isbn() << " " << s.units_sold << " " << s.revenue << " "
      << s.avg_price();
  return out;
}

double SalesItem::avg_price() const {
  if (units_sold)
    return revenue / units_sold;
  else
    return 0;
}
#endif