1. Array and Pointer
-
p[i]等于*(p + i)等于i[p] -
*(ptr + x)是在*ptr的前方第x个*ptr类型的 object,也就是前方sizeof(*ptr)个地址上的 object.
ptr1 - ptr2 返回值是一个整数,表示 ptr1 和 ptr2 储存的地址之间有多少个 *ptr 类型的 object.
-
pointer 的
>,<,==比较的是地址大小,地址越往后越大. -
对于两个 array,
arr1 = arr2是报错的,因为右边 array decay 成了一个指向其首元素的 pointer,而左边是一个 array. std 没有这样的operator=overload.
2. const keyword
-
const forbids assignment,仅支持 Initialization
-
const pointer: 形如
int * const ptr = &x;,值在 initialization 之后就不能变了. 也就是它装的 address 不能变,但是它装的 address 下的变量是可以变的,也就是可以解引用它来更改它指向的 object 的值 -
pointer to const: 形如
const int * ptr = &x;或int const * ptr = &x,值可以变,也就是它可以重新指向别的地址,但是这个指向的行为是const的x不是const变量,还是可以改变x的值,但是不能 dereferenceptr来改变x的值. -
如果要指向一个 const variable,那么必须使用 ptr-to-const
-
不允许把一个 pointer-to-const 或者 const pointer 的值传给一个 普通的 pointer。(把 const int 的值传给一个普通 int 是可以的)
-
c++ void func1(const int *ptr) { // ptr-to-const, 不能改变指向对象值 } void func2(int * const ptr) { // const ptr, 指向的地址不能改变, 可以改变指向对象值 } /* 1. 将普通指针传给要求 pointer-to-const 的函数, 函数内部无法通过这个指针修改数据. 但是原指针可以; 2. 将普通指针传递给要求 const pointer 的函数, 函数内部不能改变指针的值,但是原指针可以; 3. 把 const variable 传给参数不是 const 的函数:error */ -
reference to const: 形如
int const &ref = x;,不能用它来 change object 值,但仍可以用这个 object 的非constvariable 改 object 值. const int func()return 一个const,而 member functionint func() const表示这个 member function 不能改变 member 的值.
3. struct (C-style-ADT)
new在 dunamic memory 中创造一个 object,并 return 指向这个 object 的一个 pointer.delete z,z是一个 local pointer variable,做的是 destroyz所指向的 dynamic memory 中的 dynamic object. 在delete之后z仍然指向 heap 中的同一位置,z的值并不会改变! 但此时已经不能 dereference 它 (导致UB),但可以重新给z赋值.
4. Stream 和 C-string
-
C-style strings 就是末尾加上 null
\0的 char array.\0是 null,它的 ASCII value 为 0. -
c++ char str1[6] = {'h', 'e', 'l', 'l', 'o', '\0'}; char str2[6] = "hello"; // 等价 const char *ptr = "hello"; // 等价, 但注意必须要 const, 因为 array 的首元素地址是 const 的
如果从 "" 形式 initialize, \0 会被自动加上,但如果从 array 形式 initialize,我们必须在最后一个元素后手动加上 '\0'
-
cout由 char array 名字 decay 形成的char*会cout整个 char array 而不是首元素地址, 这是一个 standard overload. -
不要 out 并非指向一个 C string 的
char*型变量. 它也会由于 overload 一直输出到找到 null 为止 -
x += 1和++x是等价,先 +1 再 evaluate expression;和x++不等价的. -
把string 转化成 int/double:
stoi()和stod()for c++-string 以及atoi(),atof()for c-string. -
main 格式:
int main(int argc, char *argv[]) {}.cout << argv[1]的时候,argv[1]是一个地址,但是我们 cout 的是一整个 argument, 由于 c-stirng 的 cout overload. -
把 C++ string 转成 C string
const char *cstr = str.c_str();,把 C string 转成 C++ string:string str = string(cstr); -
strcpy的作用是把第二个 cstr 的值传给第一个.
c++
void strcpy(char *dst, const char *src) {
while (*dst++ = *src++) {}
}
-
Concatenate:
strcat(cstr1, cstr2)for c-string 以及str1 += str2for c++-stirng. -
compare:
strcmp(A,B)return 第一个不一样的字母的 ascii 码的大小差距. (A 比 B 小就返回负值) -
比较 c-string:
c++ if (argv[1] == "--debug") { ... } // BAD, compares addresses if (argv[1] == argv[2]) { ... } // BAD, compares addresses if (std::string(argv[1]) == "--debug") { ... } // OK, wrap one in a std::string if (argv[1] == "--debug"s) { ... } // OK, ""s suffix creates a std::string -
用 stream 型 objects 打开一个文件
c++ ifstream fin("order.txt"); ofstream fout("output.txt"); -
cin >> word会无视 newline,且会 leave newline in the stream,而getline()会 reads a blank line. -
commandline input/output Redirection:
>/<shell ./game.exe < choices.txt #input in.txt > ./game.exe #output -
Pipeline
|: 把一个 program 的 stdout 作为 stdin 输入到另一个 program.c++ ./game.exe | grep 'battle' > battles.log按自然顺序,没有优先级
-
main的 return 值:0 表示运行正常;1 表示通用的未知错误,2 表示用于命令行语法错误,126 表示命令不可执行,127 表示找不到命令,128 表示无效的退出参数,128 + N 表示通过信号 N 终止的进程,255 表示退出状态超出范围.
5. class (C++-style-ADT) and derived class
-
this不仅可以->member variable 还可以->member function.this -> scale()就是*(this).scale(). 可以不写this让 compiler 自动默认。 -
const的 object 不能使用非const的 member function
const Triangle t1(3, 4, 5);
t1.scale(); // error
- **只要是同一个 class,那么这个 class 其他 object 的 member 也可以由这个 object 的 member function access. **
- 一旦自己写了其他 ctor,compiler 自动添加的 default ctors 就失效
-
Atomic objects (int, double, bool, char, pointers) default initialization 自动赋一个 junk 值,Array objects default initialization 给每个元素自动赋一个 junk 值.
-
member initializer list:
c++
Triangle(double a_in, double b_in, double c_in)
: a(a_in), b(b_in), c(c_in) {}
如果不使用 initializer list,当 class 的成员中包括了另一个 class,compiler 就会自动调用这个另一个 class 的 default constructor ,而它有可能已经没有 default constructor 了,那么就会 error. 使用 initializer list 可以避免这个错误.
- derived class: 形如
class Bicycle: public Vehicle {};Derived class 自动继承 base class 的所有 member variables 以及 functions,但 Derived Class 无法 assess Base Class 中的 Private members. 必须通过 base class 的 public function 来 access.
protected variables 表示子类 access 的 private member.
c++
class Vehicle {
protected: /*..*/
private: /*..*/ };
- Enum: 用以存储 named int constants. 形如下. 我们可以给其中的 constants 分配的
int值,如果不 specify 则会被自动分配 0, 1, 2, ... 的值.
c++
enum Bicycletype {MOUNTAIN, ROAD, ELECTRIC, RACING};
- Derived class 的 Constructor 会 implicitly 在 initializer list 中自动调用 Base Class 的 default constructor. 也可以直接自己 custom call.
c++
Bicycle::Bicycle()
:Vehicle(2, "black", 2023), type(MOUNTAIN) {}
6. Polymorphism
-
只有 1. pointer 类型以及 2. 作为引用的 variables 才会有 dynamic type!!
-
一个 variable 的 static type 指它 compile time 的 type,也就是我们 declare 的 type; dynamic type 是 runtime 时的 type.
c++
Animal* animal = new Dog();
static type 是 Animal *, dynamic type 是 Dog *. 作为函数的参数的变量的 dynamic type 取决于 what is passed.
c++
void fp(Vehicle *vp) {cout << vp -> get_insurance_amount() << endl;} //vp 的 static type 是 Vehicle *, 因为我们这样 declare
int main() {Car mc; fp(&mc);} //这里 parameter vp 的 dynamic type 是 Car *, 因为 compile 时传进去的类型是个 Car *
-
C++ 中,by default,使用的是它的 static type 对应的 class 的成员和方法(Static Binding). 成员函数也只能接触它 static type 的成员.
-
给 member function 加上
virtual之后,这个函数就变成了一个 dynamic binding 的函数, -
virtual必须从 base class 开始,不存在 derived class 的 override 中这个 function 是virtual的但是 base class 中同一个 function 却不是,这种可能性。包括 ctor. -
对 virtual derived member function 使用
override,compiler 会检查该函数是否真的继承了个 virtual function,如果没有会报错; 使用final可以阻止进一步的继承。 -
一旦 base class 中一个 member function 是
virtual的,那么它的 derived class 中所有这个函数的 override 函数自动变成virtual的,不需要加上virtual关键词。 -
一个 pure virtual function 指的是一个以
=0为结尾 declare 的 function。表示这个 function 是没有定义的. 一个 abstract class 指包含至少一个 pure virtual function 的 class,不能 instantiate,但如果有 data member,则仍然需要一个 constructor。 -
pure abstract class,指所有函数都是 abstract functions,并且没有 data members 的 class,不需要写 constructor;且 compiler 会自动为 pure abstract class 提供 default constructor。
-
c++ Bicycle b; Vehicle* vp = &b; //upcasting Bicycle* bp = vp; //不能这样 donwcast, error Bicycle* bp = dynamic_cast<Bicycle*>(vp); //downcast
7. Container ADT
-
一个 class 的
staticvariable 是一个 private to 这个 class 的 global variable. -
operator overload:
```c++
template
os << elts[elts_size - 1] << "} ";
}
template
-
我们可以在class 内声明一个 friend function. 表示这个 function 是 class 外的 (并不是
set::...的 function),但是它被允许 access 这个 class 的 private 和 protected 的 members. -
template:
For func
c++
template <typename T>
T max(T a, T b) {return a > b ? a : b; /* > ? : 真就返回1的结果, 假就返回2的结果*/}
For class:
c++
template <typename T>
class Set{/*...*/};
每个 member variable 的框体外 definition 都要加上 template.
c++
template <typename T>
bool Set<T>::contains(T e) const {
return index_of(e) != -1;
}
- include guard:
c++
#ifndef SOMETHING.hpp
#define SOMETHING.hpp
//...
#endif
-
template class 的 declarations 和 definitions 必须在同一个文件
-
binary search: $O(log\; n)$
c++
int binarySearch(int arr[], int size, int target) {
int left = 0;
int right = size - 1;
while (left <= right) {
int mid = (left + right) / 2; // binary split!
if (arr[left] == target) {return mid;} // found!
if (arr[mid] < target) {left = mid + 1;} // not found: move side
else {right = mid - 1;}
}
return -1; // if not found: not in the array
}
- 其他 operator overload
```c++ bool operator==(const Person &p1, const Person &p2) { return p1.name == p2.name; }
template
// copy all attributes
current_capacity = rhs.current_capacity;
size = rhs.size;
for (int i = 0; i < size; i++) {
ele[i] = rhs.ele[i];
}
return *this;
}
} ```