C/C++拾遗

虚函数和纯虚函数

虚函数:virtual void fun (){………..};定义后了可以实现,并且主要是为了子类会对这个函数进行重写,从而实现多态性。声明一个基类指针对象,但指向子类实例对象,这样如果基类是虚函数,则可以根据指向的子类的不同而实现不同的方法。不使用虚函数的话,将无法使用子类重写过的函数。

纯虚函数:virtual +函数+ =0 。只声明,不会在基类完成定义,需要在子类中定义实现的方法。


重写和重载

重载

  • 相同的范围(同一个作用域中)比如同一个类中
  • 函数的名字相同
  • 函数的参数不同
  • virtual可有可无
  • 返回值可以不同(不能仅只有返回值不同,否则编译器无法分辨调用的是哪一个函数)

重写覆盖

  • 不同范围 (基类与子类)
  • 名字相同
  • 参数相同
  • 基类函数必须有virtual

重写隐藏

  • 不同范围
  • 名字相同
  • 参数不同
  • virtual可有可无

结构体和类的区别

结构体 :使用struct声明,可以包含构造函数,常数,字段,方法,属性,索引器,运算符和嵌套类型等,不过,结构是值类型。

区别:类的成员默认是私有的,而结构体的成员则是公有的。

继承类的构造顺序

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
26
27
28
29
30
31
32
33
34
#include <iostream>

using namespace std;
class Base{
public:
Base()
{
cout<<"Constructing Base\n";
}
~Base()
{
cout<<"Destructing Base\n";
}
};

class Derived: public Base{
public:
Derived()
{
cout<<"Constructing Derived\n";
}
~Derived()
{
cout<<"Destructing Derived\n";
}
};
int main() {
Derived* d = new Derived();
Base* b = d;
delete b;
delete d;
//std::cout << "Hello, World!" << std::endl;
return 0;
}

输出为:

1
2
3
4
5
Constructing Base   
Constructing Derived
Destructing Base
Destructing Derived
Destructing Base

需要先调用基类的构造函数,然后是派生类的构造函数,析构顺序则类似于出栈,刚好相反

explicit关键字

explicit的作用是用来声明类构造函数是显式调用的,禁止隐式调用。所以只用于修饰单参构造函数。因为无参构造函数和多参构造函数本身就是显式调用的。

隐式转换:A a=True ; (原来的的构造函数是A(bool para){}) 这样的隐式转换使代码的可读性变差。使用explicit 后调用构造函数则必须使用 A a(True)这种显式方式来调用。

构造函数初始化列表

compressed_sparse_row_graph(const ProcessGroup& pg = ProcessGroup())
: m_process_group(pg), m_distribution(parallel::block(pg, 0)) {} //fun():使用初始化列表进行初始

构造函数为compressed_sparse_row_graph()在()里面申明pg,然后在:后面使用pg来对m_process_groupm_distribution()进行初始化。

const 引用形参

使用const来修饰引用参数,无法通过修改形参来改变实参。

const int &r = a 无法通过r这个引用去修改a的值。

STL容器

容器:

即是数据结构,类似于Python的pandas的DataFrame等。Python自带的dict,list、tuple等。数据结构不止是简单的array。

顺序容器

  • vector 后部插入/删除,直接访问
  • deque 前/后部插入/删除,直接访问
  • list:双向链表,任意位置插入/删除

关联容器

  • set:快速查找,无重复元素
  • multiset:快速查找,可有重复元素
  • map : 一对一映射,无重复元素,基于关键字查找 类似python的dict
  • multmap:一对一映射,可有重复元素,基于关键字查找

文件流

头文件:<fstream> 包含三个类:

  • ofstream :文件写操作,从内存写入存储设备 output
  • ifstream : 文件读操作,从存储设备读的内存中 input
  • fstream :读写操作

memset()

需要包含的头文件是

作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。

memset(struct/array,value,size) 最后一个参数是填充对象的前size个元素

str 的find_first_of() 和substr

find_first_of(char,begin_pos) 从begin_pos开始寻找第一个char

string_obj.substr(int begin_pos, int len) 截取begin_pos开始长度为len的子字符串。

指针常量和常量指针

常量指针(const pointer):

​ 指针是一个常量指向的地址是常量不能变,而地址存储的值可以改变。

​ 申明int *const p

​ 从右往左读,const 限定p对象是一个常量,而常量的具体类型则是是一个指向int类型的指针

​ 从右往左读,遇到p就替换成“p is a ”遇到*就替换成“point to” 读作p is a const pointer point to int

指向常量的指针 (pointer to const )

​ 指针是一个变量,指向的类型是常量.(通常用在形参中,使得形参指针指向的数据不会被修改)

​ 申明int const *p 或者const int *p分别读作:p is a point to int const. 与 p is a point to const int.

成员变量的初始化顺序

成员变量的初始化顺序,只与在类中声明的顺序有关,与在初始化列表中的顺序无关。 先声明,先初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
private:
int n1;
int n2;
public:
A():n2(0),n1(n2+2){}
void Print(){
std::cout<<"n1:"<<n1<<",n2:"<<n2<<std::endl;
}
};
int main(int argc, char* argv[]){
A a;
a.Print();
return 0;
}

先初始化n1,因为n2是随机值,所以n1也是随机值+2,之后初始化n2为0。

容器中的end()

begin()迭代器指向第一个元素,end()迭代器指向尾元素的下一个位置,并不是末尾元素。对迭代器理解为指针,所以获得迭代器的使用*来获得指向的值。

max_element(first, last) 比较的区间为[first, last)