C++笔记


本文用来记录学习C++过程中的一些笔记


本文主要用来自己学习,由于本人水平有限,本文难免会有不当之处,欢迎读者批评指正

基本知识

输入字符串

  • cin >> aStr只能用于输入一个单词
  • 如果想要输入一整行,则要用getline(cin, aStr)
  • 如果想要清空(flush)cin,可以用ignore(numeric_limits<streamsize>::max(), '\n')来清除直到\n的所有字符,使用这个函数要#include <limits>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Testing string class input and output (TestStringIO.cpp) */
#include <iostream>
#include <string> // Need this header to use string class
#include <limits>
using namespace std; // Also needed for <string>

int main() {
string message("Hello");
cout << message << endl;

// Input a word (delimited by space) into a string
cout << "Enter a message (no space): ";
cin >> message;
cout << message << endl;

cin.ignore(numeric_limits<streamsize>::max(), '\n');
// flush cin up to newline (need <limits> header)

// Input a line into a string
cout << "Enter a message (with spaces): ";
getline(cin, message); // Read input from cin into message
cout << message << endl;
return 0;
}

字符串操作

函数基本和Java一样。

搜索和替换string中的字符:用<algorithm>中的replace()函数。

1
2
3
4
5
#include <algorithm>
......
string str("Hello, world");
replace(str.begin(), str.end(), 'l', '_');
cout << str << endl; // "He__o, wor_d"

格式化输入/输出

使用Header<iomanip>

  • setw(int field-widht):将下一次IO操作设置为制定宽度。非持久的操作,必须每次IO前调用一次。
  • setfill(char fill-char):用指定字符填充空闲空间。
  • left|right|internal: set the alignment:设置对齐方式。
  • fixed/scientific:制定符点数用“定点表示法” (e.g, 12.34) 还是用科学计数法(e.g., 1.23e+006)
  • setprecision(int numDecimalDigits):指定小数点后保留几位。
  • boolalpha/noboolalpha (for bool):指定是用字符(true/false)显示bool型还是用数字(0/1)来显示。

输出示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Test Formatting Output (TestFormattedOutput.cpp) */
#include <iostream>
#include <iomanip> // Needed to do formatted I/O
using namespace std;

int main() {
// Floating point numbers
double pi = 3.14159265;
cout << fixed << setprecision(4); // fixed format with 4 decimal places
cout << pi << endl;
cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
// setw() is not sticky, only apply to the next operation.
cout << setfill('-');
cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
cout << scientific; // in scientific format with exponent
cout << pi << endl;

// booleans
bool done = false;
cout << done << endl; // print 0 (for false) or 1 (for true)
cout << boolalpha; // print true or false
cout << done << endl;
return 0;
}
1
2
3
4
5
6
7
//output
3.1416
| 3.1416| 3.1416|
|--3.1416|----3.1416|
3.1416e+00
0
false

输入示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Test Formatting Input (TestFormattedInput.cpp) */
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

int main() {
string areaCode, phoneCode;
string inStr;

cout << "Enter your phone number in this format (xxx)xxx-xxxx : ";
cin.ignore(); // skip '('
cin >> setw(3) >> areaCode;
cin.ignore(); // skip ')'
cin >> setw(3) >> phoneCode;
cin.ignore(); // skip '-'
cin >> setw(4) >> inStr;
phoneCode += inStr;

cout << "Phone number is (" << areaCode << ")"
<< phoneCode.substr(0, 3) << "-"
<< phoneCode.substr(3, 4) << endl;
return 0;
}

C++的structs

C++的structs和class的唯一区别是:structs的成员默认是public的,而class默认是private的。structs默认public-继承,class默认private-继承。

inline Function vs. #define 宏

使用宏可能引发一些错误,对比如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Test #define macro (TestMacro.cpp) */
#include <iostream>
using namespace std;

#define SQUARE(x) x*x // Macro with argument

inline int square(int x) { return x*x; } // inline function

int main() {
cout << SQUARE(5) << endl; // expand to 5*5 (25)
int x = 2, y = 3;
cout << SQUARE(x) << endl; // expand to x*x (4)

// Problem with the following macro expansions
cout << SQUARE(5+5) << endl; // expand to 5+5*5+5 - wrong answer
cout << square(5+5) << endl; // Okay square(10)
cout << SQUARE(x+y) << endl; // expand to x+y*x+y - wrong answer
cout << square(x+y) << endl; // Okay
// can be fixed using #define SQUARE(x) (x)*(x)

cout << SQUARE(++x) << endl; // expand to ++x*++x (16) - x increment twice
cout << x << endl; // x = 4
cout << square(++y) << endl; // Okay ++y, (y*y) (16)
cout << y << endl; // y = 4
}

OOP基础

关键字 “this”

  • C++中的this是当前实例的一个指针,所以要用this->field来引用域变量
  • 由于编译器的一些原因,不要在C++中给变量名以下划线开头命名

“const” 成员函数

在成员函数的末尾加入关键词const,就不能在这个函数中修改该对象的任何成员。

1
2
3
4
5
double getRadius() const {  // const member function
radius = 0;
// error: assignment of data-member 'Circle::radius' in read-only structure
return radius;
}

构造器的member initializer list

可以用member initializer list来初始化private member:

1
Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }

  • Member initializer list放在构造器头部的后面,并用冒号:隔开.
  • 每一个initializer遵循data_member_name(parameter_name)的格式
  • 使用member initializer list更efficient

销毁器 Destructor

  • 与构造器类似,函数名字和类名一样,但是带有一个前缀~,如~Circle()
  • 当一个对象被销毁时,Destructor被隐示调用
  • If your class contains data member which is dynamically allocated (via new or new[] operator), you need to free the storage via delete or delete[].
1
2
3
4
5
6
class MyClass {
public:
// The default destructor that does nothing
~MyClass() { }
......
}

拷贝构造器

If you do not define a copy constructor, the compiler provides a default which copies all the data members of the given object.

1
2
3
4
5
6
7
8
9
10
11
Circle c4(7.8, "blue");
cout << "Radius=" << c4.getRadius() << " Area=" << c4.getArea()
<< " Color=" << c4.getColor() << endl;
// Radius=7.8 Area=191.135 Color=blue

// Construct a new object by copying an existing object
// via the so-called default copy constructor
Circle c5(c4);
cout << "Radius=" << c5.getRadius() << " Area=" << c5.getArea()
<< " Color=" << c5.getColor() << endl;
// Radius=7.8 Area=191.135 Color=blue

为了防止表示外泄,最好在拷贝构造器中采用传入const引用参数的方式

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
private:
T1 member1;
T2 member2;
public:
// The default copy constructor which constructs an object via memberwise copy
MyClass(const MyClass & rhs) {
member1 = rhs.member1;
member2 = rhs.member2;
}
......
}

Copy 赋值操作符(=)

  • 与java不同,C++里的对象赋值并不是赋值引用,而是拷贝了一个新的对象。
  • The copy assignment operator differs from the copy constructor in that it must release the dynamically allocated contents of the target and prevent self assignment. The assignment operator shall return a reference of this object to allow chaining operation (such as x = y = z).
1
2
3
4
5
6
7
8
9
10
11
12
Circle c6(5.6, "orange"), c7;
cout << "Radius=" << c6.getRadius() << " Area=" << c6.getArea()
<< " Color=" << c6.getColor() << endl;
// Radius=5.6 Area=98.5206 Color=orange
cout << "Radius=" << c7.getRadius() << " Area=" << c7.getArea()
<< " Color=" << c7.getColor() << endl;
// Radius=1 Area=3.1416 Color=red (default constructor)

c7 = c6; // memberwise copy assignment
cout << "Radius=" << c7.getRadius() << " Area=" << c7.getArea()
<< " Color=" << c7.getColor() << endl;
// Radius=5.6 Area=98.5206 Color=orange
  • The copy constructor, instead of copy assignment operator, is used in declaration:
1
2
Circle c8 = c6;  // Invoke the copy constructor, NOT copy assignment operator
// Same as Circle c8(c6)

//TODO