AOP-Chap16-Strings and IO Revisited

1 Strings

  • C++ provides a string class (std::string)
  • argv is still a char ** just as it is in C
#include <string>
  • string class encapsulates the sequence of bytes that form a string into an object that provides a variety of methods and operators to operate on that type
    • length() method
    • operators such as += --> append one string to the end of another
    • operators such as [] --> index into the string, returning a reference to the requested((const) char &) character, can be used to modify the contents of a string
    • constructors --> takes a const char * (i.e., a C-style string) as an argument
//create a C++ string object (locally in the current frame) and initialize it with the (C) string literal
std::string s("Hello World");

full reference on C++'s string -> http://www.cplusplus.com/reference/string/string/

1.1 Cautionary Example 反例

  • substr用法
/*
形式:s.substr(pos, n);
解释:返回一个string,包含s中从pos开始的n个字符的拷贝(pos的默认值是0,n的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
补充:若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
*/
#include<string>
using namespace std;
int main() {
  string s("12345asdf");
  string a = s.substr(0,5);
}  
//output: 12345
  • reverse a string
    • ineffcient写法(假的tail recursion)
#include <string>
//This code is terribly inefficient
std::string reverse(std::string s, std::string ans) {
	if (s.length() == 0) { 
		return ans;
	}
	return reverse(s.substr(1), s[0] + ans);
}
//Note that the next function is not recursive.
//It calls the other (overloaded) reverse function, not itself.
std::string reverse(std::string s) {
	return reverse(s, "");
}	
1. not actually tail recursive, so the compiler cannot apply tail call optimization to it
2. the frames for reverse have four string objects (s, ans, as well as temporary objects for s.substr(1) and s[0] + ans), which have nontrivial destructors
3. objects must be destructed after the recursive call of reverse returns
4. create many new objects and perform significant copying --> copy s.substr(1), copy s[0]+ans, then copy the temporary objects into the parameters of the recursive call
  • efficient 写法
//recursion
#include <string>
std::string reverse(const std::string & s, std::string & ans, size_t ind) {
	if (ind == s.length()) { 
		return ans;
	}
	ans[ind] = s[s.length() - ind - 1]; 
	return reverse(s, ans, ind + 1);
}
//Note that the next function is not recursive.
//It calls the other (overloaded) reverse function, not itself.
std::string reverse(std::string s) {
	std::string ans(s.length(), ’\0); //产生一个新object
	return reverse(s, ans, 0);	
}	
#include <string>
std::string reverse(std::string s) {
	std::string ans(s.length(), ’\0);
	for (size_t i = 0; i < s.length(); i++) {
		ans[i] = s[s.length() - 1 - i];
	}
	return ans;
}		
  • 避免多次复制、destruct对象,consider ways to pass parameters by reference (or const reference) instead of value, as well as where temporary objects are created, and how they might be eliminated

2 Output

  • C approach requires us to write a function that takes in the data to be printed.
  • OO approach lets a class define how to print itself with a method encapsulated inside of it
  • C++重载operator :
    • fundamental type for output operations is a std::ostream
    • << operator (stream insertion operator) is overloaded to work with it as the left-hand operand with a variety of possible types for its right-hand operand
  • std::cout代替stdout,也是一个std::stream; std:cerr代替stderr
#include <iostream> //包含std::cout, the std::ostream type, and the built-in overloadings of <<
#include <cstdlib> //definition of EXIT_SUCCESS

int main(void) {
	std::cout << "Hello World\n"; 
	return EXIT_SUCCESS;
}	
#include <iostream>
#include <cstdlib>

int main(void) {
	for (int i = 0; i < 10; i++) {
		std::cout << "i = " << i << "\n";
		std::cout << "and i / (i + 1) = " << (i / (double)(i + 1)) << "\n";
	}
	return EXIT_SUCCESS;
}
//C++不需要写格式说明符%d %f; C++ << is overloaded on multiple types,分别对应不同的function	

2.1 Return Type of Stream Insertion

  • Each << operator evaluates to a value, which in this case (and by convention, in general for stream operators) is its left operand
  • so the next << operator again has std::cout as its left operand
//implementation of << with int as the right operand type
std::ostream & operator<<(std::ostream & stream, int num) {
	char asString[16]; //decimal representation of int < 16 bytes
	snprintf(asString, 16, "%d", num); //convert the integer to a sequence of characters
	stream.write(asString, strlen(asString)); //write those characters to the underlying ostream
	return stream;//return the original stream
}	
  • If make the overloaded operator return the ostream & that was passed in as its left operand, << will be usable in the “normal” way—that is, you can chain multiple of your << operators and/or mix them with other overloadings in a single statement 必须返回左边有意义type才能chain
  • If make your << return void (as one might naïvely do), you will not be able to chain them together

2.2 Writing Stream Insertion for Your Own Classes

  • writing it inside of the class would require the object being printed to be the left operand instead of the right—for operators that are members of classes, the left operand is this
  • must write a method outside of the class 当不想返回left operand想返回右边
// << operator is now outside the class,无法访问class内部
std::ostream & operator<<(std::ostream & stream, const MyClass & data) {
	//whatever it takes to print things (elided)...
	return stream;
}

class MyClass {
	//declarations of fields, methods, etc.
	friend std::ostream & operator<<(std::ostream & stream,	const MyClass & data);
};	
  • C++允许一个类declare functions or class as its friend. 这样function or class is allowed access to the private elements of the declaring class. friend declaration is placed inside of the class
  • declare the friendship by writing the entire prototype of the function
  • a function with the same name but different parameter types as a friend would not itself be a friend (unless also declared as such explicitly)
  • 除该情况外不许使用:Using it for operators that are overloaded and are, in principle, part of the class but are just declared outside of the class due to the ordering of the parameters is a legitimate use of friend

2.3 Object Orientation of This Approach

  • the << and >> operators ask the stream object to perform output and input (respectively) with their right operands as arguments

2.4 Controlling Formatting

  • current format state有两种方法修改
    1. insert special values (called manipulators) with the << operator
    2. call methods on the stream
int x = 42;
std::cout << x << "\n"; //42 默认10进制
std::cout << std::hex << x << "\n";//2a
std::cout << std::oct << x << "\n";//52 8进制
std::cout << std::dec << x << "\n"; //42 修改回来很重要
  • put a stream back into decimal mode when you are done printing things in other modes
//set the field width of cout to five, meaning that an output conversion that uses field width (e.g., printing integers) will print at least five characters
std::cout.width(5);
  • extra characters get printed --> fill method and passing in the desired character
  • floating point precision --> precision method

3 Input

  • use stream objects (in this case, istreams), and the stream extraction operator, >>
  • stdin被std::cin代替
int x;
std::cin >> x; //read an integer from standard input,默认10进制,修改-->std::cin >> hex
  • 可以重载stream extraction operator for input streams和classes
std::istream & operator>>(std::istream & stream, MyClass & data) { //data是not const, as you plan to modify it
	//whatever it takes to read things (elided)...
	return stream;
}	
  • 仍然要使用friend,才能modify the internal data directly in ways that may not be possible through the external interface

3.1 Errors

  • When an operation produces an error, it sets the stream’s error state.
  • This error state persists, causing future operation to fail, until it is explicitly cleared.
  • When an error occurs, the input that could not be converted is left unread, so future read operations can try to read it (after the error state is cleared)
int x;
std::cin >> x;
if (!std::cin.good()) { //check if any errors happened
	std::cin.clear(); //clear the error state so that subsequent operations can succeed
	std::string badinput;
	std::cin >> badinput; //read a string, which could also fail (for example, if we have reached the end of the file)
	if (!std::cin.good()) {
  		std::cerr << "Cannot read anything from cin!\n";
	}
	else {
		std::cerr << "Oops! " << badinput << " wasn’t an int!\n";
	}
}	
  • input streams三种类型failure
    1. end of file --> checked with the .eof() method
    2. logical errors on the operation -> such as an inability to perform the proper conversion --> check with the .fail() method
    3. errors with the underlying I/O operation --> check with the .bad() method if .fail() returned false
  • 当用>>读一个string,只读一个单词而不是一行,遇到空格停止,要用std::getline function(不是member of any class), which takes an input stream reference and a string reference and fills in the string with the next line of input from the stream (unless an error occurs)

4 Other Streams

  • C++’s stream library has classes that work with files
  • C++ also has streams that collect the data into an internal buffer (or extract it from the buffer), allowing us to manipulate the data within the program (analogously to C’s snprintf and sscanf functions)
/*
将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断
str -- 目标字符串。
size -- 拷贝字节数(Bytes)。
format -- 格式化成字符串。
... -- 可变参数。
(1) 如果格式化后的字符串长度小于等于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0;
(2) 如果格式化后的字符串长度大于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,返回值为欲写入的字符串长度。
*/
int snprintf ( char * str, size_t size, const char * format, ... );

4.1 Files

  • std::ifstream (for reading), std::ofstream (for writing), and std::fstream (for reading and writing) classes
  • classes have default constructors (which create an object with no file associated with it—you can open one later with the open method) and constructors that take a const char * specifying the file name (they also take a second parameter for the mode, but it has an appropriate default value)
  • 打开的文件用close method关闭
  • 这些类都在#include <fstream>
  • When using these classes, data is written to the file with the stream insertion operator (<<) and read from the file with the stream extraction operator (>>)
  • an ofstream is a special type of ostream and thus is compatible with things that expect pointers or references to ostreams
  • An fstream is compatible with both ostream and istream, so we can use both << and >> on it

4.2 String Streams

  • get the resulting string into a variable (for <<) or extract the fields(字段) from a string variable (for >>) --> 使用std::stringstream class
  • 使用string stream把string构建为一个variable --> default construct one and then use the << to add elements to the stream --> Whenever we are done building the string up, we can use the .str() method to get a std::string with all the text we have inserted into the stream
  • 使用string stream把string分解成formatted input --> use >> to extract pieces from the string the string stream holds --> construct the string stream with the constructor that takes a string, passing in the string we want to pull apart --> use >> to extract fields into variables of appropriate types --> extraction could fail, so we must check for errors
  • 以上两种行为是并存的,不冲突
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值