本文共 6017 字,大约阅读时间需要 20 分钟。
关于C++的内容,都是在已经了解了C语言的基础之上总结的,所以有不少C++的基础,因为也是C语言的基础,所以不会特意说明。
首先是一个简单的例子:
#includeint main(){ int v1 = 0, v2 = 0; std::cout << "Enter two numbers:" << std::endl; std::cin >> v1 >> v2; std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl; return 0;}
cout是标准输出,cin是标准输入,此外还有cerr是标准错误,clog是标准日志记录,对应的头文件:
namespace std _GLIBCXX_VISIBILITY(default){_GLIBCXX_BEGIN_NAMESPACE_VERSION /** * @name Standard Stream Objects * * The <iostream> header declares the eight standard stream * objects. For other declarations, see * http://gcc.gnu.org/onlinedocs/libstdc++/manual/io.html * and the @link iosfwd I/O forward declarations @endlink * * They are required by default to cooperate with the global C * library's @c FILE streams, and to be available during program * startup and termination. For more information, see the section of the * manual linked to above. */ //@{ extern istream cin; /// Linked to standard input extern ostream cout; /// Linked to standard output extern ostream cerr; /// Linked to standard error (unbuffered) extern ostream clog; /// Linked to standard error (buffered)#ifdef _GLIBCXX_USE_WCHAR_T extern wistream wcin; /// Linked to standard input extern wostream wcout; /// Linked to standard output extern wostream wcerr; /// Linked to standard error (unbuffered) extern wostream wclog; /// Linked to standard error (buffered)#endif //@} // For construction of filebuffers for cout, cin, cerr, clog et. al. static ios_base::Init __ioinit;_GLIBCXX_END_NAMESPACE_VERSION} // namespace
可以看到在cout、cin之前加了std,它是命名空间的名称,使用它是为了防止全局命名的冲突,这样写当然比较麻烦,如果一直使用的都是std这个命名空间,就可以直接在开头导入:
using namespace std;
还有一个endl,它是一个操纵符,写入endl的效果是结束当前行,并将与设备关联的缓冲区中的内容刷写到设备中,而不是仅停留在内存。
<<和>>是输出运算符和输入运算符。<<接收两个运算对象,左边是ostream对象,右边是需要输出的值。<<运算符的返回值是左边的ostream对象,这样才可以像代码中那样连续多次使用<<。>>也类似,接收两个对象,左侧是istream对象,右侧是一个普通对象来接收读入的数据,并返回左侧的istream对象。
代码执行的结果:
F:\Codes\cppprimer>IoStream.exeEnter two numbers:1 2The sum of 1 and 2 is 3F:\Codes\cppprimer>IoStream.exeEnter two numbers:1 2aThe sum of 1 and 2 is 3F:\Codes\cppprimer>IoStream.exeEnter two numbers:a bThe sum of 0 and 0 is 0
从上面的程序中其实是可以看到一些可疑的点的,这个涉及更复杂的内容,将在后续进一步介绍。
这里只介绍与C语言有差异的。
首先是for:
int main(){ for (int i = 0; i < 10; i++) { cout << i << endl; } return 0;}
主要的区别在于i这个变量,C++中可以直接放到for循环语句中;C语言中其实也可以这么用,但是似乎有版本限制,且一般也不这么用。这里还需要注意i只在for循环对应的代码块中才有效,在其外是无效的。
其次是结合输入的控制流:
int main(){ int sum = 0; int value; while (cin >> value) { sum += value; } cout << "The sum is: " << sum << endl; return 0;}
执行结果:
F:\Codes\cppprimer>Control.exe1 2 3^ZThe sum is: 6
这里的while循环会一直持续,直到按下Ctrl+z再加Enter为止,这表示了输入的结束,然后执行后续的打印结果。这里是while的例子,cin也可以用在if中:
int main(){ int value; if (cin >> value) { cout << "The input: " << value << endl; } return 0;}
这里只获取第一个输入,然后打印值,结果如下:
F:\Codes\cppprimer>Control.exe1The input: 1
C语言当也可以通过scanf完成类似的写法
类用来定义自己的数据结构及关联的操作。下面是一个例子:
class Sales_item { // these declarations are explained section 7.2.1, p. 270 // and in chapter 14, pages 557, 558, 561 friend std::istream& operator>>(std::istream&, Sales_item&); friend std::ostream& operator<<(std::ostream&, const Sales_item&); friend bool operator<(const Sales_item&, const Sales_item&); friend bool operator==(const Sales_item&, const Sales_item&);public: // constructors are explained in section 7.1.4, pages 262 - 265 // default constructor needed to initialize members of built-in type Sales_item() = default; Sales_item(const std::string &book): bookNo(book) { } Sales_item(std::istream &is) { is >> *this; }public: // operations on Sales_item objects // member binary operator: left-hand operand bound to implicit this pointer Sales_item& operator+=(const Sales_item&); // operations on Sales_item objects std::string isbn() const { return bookNo; } double avg_price() const;// private members as beforeprivate: std::string bookNo; // implicitly initialized to the empty string unsigned units_sold = 0; // explicitly initialized double revenue = 0.0;};
几点说明:
类使用class关键字定义;
>>,<<(这两个在这里指的是输入输出运算符,不是位运算符),<和==这些基本运算符被重载(Override)了,但是因为它们其实不是当前类拥有的接口,所以不能直接放到类里面,需要作friend声明。
public声明类公开的接口,private声明类的私有数据;
第一个public下是构造函数;
第二个public下是普通的公开接口;
这里有几个问题需要解决。
一是为什么需要将==等运算符Override?原因很简单,因为对于Sales_item这个自定义的数据类型,两个类对象是无法比较的,如下面的代码:
int main(){ Sales_item item1, item2; if (item1 == item2) std::cout << "==" << std::endl; else std::cout << "!=" << std::endl; return 0;}
编译时直接报错:
F:\Codes\cppprimer\1\add_item.cc: In function 'int main()':F:\Codes\cppprimer\1\add_item.cc:37:15: error: no match for 'operator==' (operand types are 'Sales_item' and 'Sales_item') if (item1 == item2)
可以看到直接提示没有匹配的operator==。
二是Override的时候为什么还要将operator==设置为友元,这主要就得看它的实现:
inline booloperator==(const Sales_item &lhs, const Sales_item &rhs){ // must be made a friend of Sales_item return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue && lhs.isbn() == rhs.isbn();}
从代码可以看到,只有当Sales_item中的units_sold、revenue和isbn()函数的返回值都相等,才表示两个Sales_item对象相等。但是问题在于units_sold和revenue是私有变量,operator==是不能直接访问的。为了访问能够成功,在定义Sales_item的时候就需要显式地声明operator==为友元。这也是为什么operator!=不需要声明为友元的缘故,如下所示:
inline booloperator!=(const Sales_item &lhs, const Sales_item &rhs){ return !(lhs == rhs); // != defined in terms of operator==}
在operator!=的实现中不需要访问Sales_item的私有数据,也就不需要声明为友元了。
三是为什么operator+=却被定义成了Sales_item的公共接口,还有一个operator+放在了Sales_item定义之外:
// nonmember binary operator: must declare a parameter for each operand// assumes that both objects refer to the same ISBNSales_itemoperator+(const Sales_item& lhs, const Sales_item& rhs){ Sales_item 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}
关于这个问题,目前没有找到答案。似乎可以是成员变量、也可以不是成员变量。
此外还有很多的知识点,比如构造函数、引用等,后面深入的时候再说明。
转载地址:http://akodz.baihongyu.com/