C++八股大杂烩

C++

1 语法&特性

返回值-NRV

有一条语句,A a = f();其中 f()是一个函数,函数里边申请了一个 A 的对象 b,然后把对象 b 返回。在对象返回的时候,一般情况下要调用拷贝函数,把函数 f()里边的局部对象 b 拷贝到函数外部的对象 a。但

NRV具名返回值优化(Named Return Value)简单的说就是,如果用了 NRV 优化,那就不必要调用拷贝构造函数,编译器可以这样做,把 a 的地址传递进函数 f(),然后不让 f()申请要返回的对象 b 的空间,用 a 的地址来代替 b 的地址,这样当要返回对象 b 的时候,就不必要拷贝了,因为 b 就是 a,省去了局部变量 b,省去了拷贝的过程。

指针传参

​ 指针作为参数传递,也是传值,即拷贝一份指针。这同样意味着你在函数中对指针的操作,并不会真正改变原指针。这里要注意理解:不改变的,是指针指向哪里,但是你却可以通过这个指针,真实的改变原来指针指向的内容。

​ 如果你想修改一个值,你可以传递指向它的指针(或引用)。因此如果你想修改指针的值(即指针的指向),那么你就要传递指向指针的指针(或指针的引用)。

​ 但是要注意,如果你修改了指针的指向,那么原来指针的指向也会变,这就意味着,原来指针指向的那一块内存区域可能无法引用了,那就会造成内存泄漏。

(1) 语法
  • 一些“关键字”:inline(外部函数变为内联)、const(不修改)、default()、explict(不隐式类型转换)、virtual(虚函数、虚继承)、static(类成员/静态成员)、using(可以在基类中隐藏父类的 public 继承来的东西)
  • 初始化列表:构造函数后以:开始,进行初始化。
    1. 静态成员只能在类内定义,类外初始化,不能出现在初始化列表中(因为一个类只含有一份?)
    2. 基类的构造函数,也在初始化列表中调用D(int a, int b, int c) : B(a, b), _c(c)(如果基类没有默认构造函数,那子类必须显示调用)
    3. 初始化顺序只看声明顺序(以及构造函数调用顺序),与初始化列表出现顺序无关。(注意区别,跟出现次序有关的是多继承时,构造函数的调用顺序)
    4. 子类只关心父类的初始化,不管再往上几辈的事,爷爷类自有父类负责(虚基类除外:子类还要调用虚基类的构造函数来初始化虚基类子对象,每个低层次的类都要写,但是实际上只有最派生类执行)【最派生类】:建立对象时所指定的类
  • 构造与析构函数
    1. 构造函数调用顺序:虚基类 \(\Rarr\) 父类(按声明左到右) \(\Rarr\)客人(类类型数据,按定义前到后)\(\Rarr\) 自己。析构顺序与之相反
    2. 不管显示还是隐式,基类总是要调用父类的构造函数,以及析构函数的。因此可以用子类的指针来析构父类,但父类的指针不会析构子类
  • 类型适应:当且仅当
  • 继承不会继承基类的构造和析构函数;
  • 虚继承:虚继承即让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类。目的是解决菱形继承问题\(\Rarr\)同名虚基类,在对象中只会产生一份虚基类子对象(全部父类加上子类,共享一个虚基类子对象)
(2) 内存布局
  • 成员函数在代码区,不占有对象的内存。成员函数中定义的局部变量是“共享的”
  • 有虚函数的,对象首块内存会存放一个指向虚表的指针。可以(void **)(*(void**)&obj)
  • 有继承的,子类中先出现的是父类中的数据成员(基类子对象),然后紧跟着是自己的数据成员
  • 如果父类中有虚函数,子类也会有一个虚表,如果没有重写父类的虚函数,那虚表中项目就指向父类的虚函数,如果重写了,那就指向子类的虚函数
(3) 常见问题
  1. 拷贝构造函数参数:
  2. 深浅拷贝:
  3. 虚构造函数与虚析构函数:

关键字和上下文关键字

// delete
void func(int)=delete;
// override, final
void f() override final;

类模板与友元函数

参考这里

// 模板类中声明友元函数共有四种:
template <typename T>
class A{
public:
	friend void f1();			// 1.不需要模板参数的,非模板函数
	friend void f2(A<T>& a);	// 2.需要模板参数的,非模板函数
	friend void f3<T>(A<T>& a);	// 3.需要模板参数的,模板函数
	template <typename U>		// 4.需要模板参数且自带参数的模板函数
	friend void f4(A<U>& a);
private:
	T v;
};

不要在类内声明的是第二种,在类外定义的却是第三种了。

智能指针

Lambda 表达式

auto foo = [capture](parameters)->return_type {func_body}

  • [capture] 用来捕获表达式外部的变量:

    1. [ = ] :以值(拷贝)的方式捕获所有外部变量,函数体内可以访问,但是不能修改。

    2. [ & ] :以引用的方式捕获所有外部变量,函数体内可以访问并修改(需要当心无效的引用);

    3. [ var ] :以值(拷贝)的方式捕获某个外部变量,函数体可以访问但不能修改。

    4. [ &var ] :以引用的方式获取某个外部变量,函数体可以访问并修改

    5. [ this ] :捕获 this 指针,可以访问类的成员变量和函数

    6. [ =,&var ] :引用捕获变量 var,其他外部变量使用值捕获。

    7. [ &,var ] :只捕获变量 var,其他外部变量使用引用捕获。

  • (parameters):即自定义函数里面的参数,只能在表达式的封闭范围内用

  • 返回值可以自动推断

2 库与函数速查

getline()

  1. 有两个 getline()函数,一个在<istream>里面,通过(输入流)成员调用的方式指出输入流,一个在<string>里面,为顶层函数,在参数列表中指出输入流

  2. getline()实际读取的为(n - 1)个字符,且会把终止符从流中删除

  3. 读到文件尾返回eofbit

// # include<istream> // 注意是char*,同时要指出读入的size
istream& getline (char* s, streamsize n, char delim );
// # include<string>
istream& getline (istream&  is, string& str, char delim);

get()

  1. 与 getline()区别在于,读到 delim 字符后,会中止并将其保留在流中,这就会被下一个用户读到

  2. 只有<istream>版本

// 依次为:single character (1),c-string (2),stream buffer (3)
int get(); istream& get (char& c);
istream& get (char* s, streamsize n, char delim);
istream& get (streambuf& sb, char delim);

正则表达式

<regex>库是 C11 中新增的特性,下面给出一些使用的例子

regex:定义一个正则表达式类,如regex rx("^[0-9]");

match_result

3 标准库 STL

黑马STL 底层数据结构总结

数组

(1) vector

🌟vector 小指南(附带一些新手错误)

  • vector 的大小。里面似乎存放的只是几个指针而已,start、fin 等。在使用umap时候发现的

string 类

string 的常用操作

栈与队列

(1) priority_queue

cpp-referencecplusplus

template<
    typename T,	// 类型
    typename Container = std::vector<T>,
    typename Compare = std::less<typename Container::value_type>
> class priority_queue;

优先队列的底层实现是二叉堆,插入时,让使 Compare 返回 true 的元素下沉(sink)

使用时容易模糊的就在于,Compare 怎么定义(讨论的是自定义类型,而非 POD)。一般的策略有:在类型中重载 < 运算符,则即可缺省 compare,或定义仿函数

//(1) Comp缺省,自定义类型中,重载或友元重载小于 < 运算符
struct ListNode {
    bool operator< (const ListNode&){}
    friend operator< (const ListNode&, const ListNode&){}
}
//(2) Comp为仿函数(即定义一个类Comp,然后重载它的括号运算符)
Class Comp{
    bool operator()(const T&, const T&){}}

常用的操作有push(), pop(), top(), empty()

集合 与 映射

(1) set

cpp-reference ⭐[set 博客总结](c++ stl 库中的 set - 然终酒肆 - 博客园 (cnblogs.com))

template<
    typename Key,
    typename Compare = std::less<Key>,
    typename Allocator = std::allocator<Key>
> class multiset;

注意四个版本:set, multiset, unordered_set, unordered_multiset

默认有序是升序,(只需使用 rbegin()rend()就能的到逆序的)

常用操作:insert、find、count、clear、empty

(2) map

map 用法详解

默认按关键字升序,STL 中的有序均是升序,因此需要重载的只是小于号 \(<\)

链表

(1) list
template<
    typename T,
    typename Allocator = std::allocator<T>
> class list;

双向链表

front、back、push_back、pop_front、insert、erase、remove_if、sort、unique、reverse

(2) forward_list

单项链表

posted @ 2024-06-16 01:16  开宝特攻  阅读(66)  评论(0编辑  收藏  举报
Back to Top Button