C++ 面试知识点

2018-09-25  本文已影响0人  林逸凡_lyf

不定期整理一些C++的知识点

C++是静态类型,即在编译阶段检查类型

引用和const变量必须被初始化

多态是通过虚函数实现的,虚函数的实现机制是虚函数表,虚函数表一般存放在内存的最头部

const对象不能调用类中的非const成员函数,将成员变量定义为mutable(可变数据成员)可以使其在const成员函数中被修改(其作用是使成员变量对于外部类来说不能修改,但内部可以对其进行修改)

struct的默认访问权限是public,class则是private

解引用迭代器来获得它指向的元素(*itr),it->mem() == (*it).mem()

cout << *iter++ << endl; == cout << *(iter++) << endl;这种写法更加简洁,应该多使用

定义数组形参:

void print(int*, size_t size); 
void print(const int[], size_t size); 
void print(const int[10], size_t size); //因为无法判断数组的长度,所以需要把长度也作为形参
void print(int (&arr)[10]); //数组的引用作为形参必须加括号, 且数组确定
void print(int (*matrix)[10], int rowSize); //传入多维数组也必须加括号, 且第二维长度确定
void print(int matrix[][10], int rowSize);

使用initializer_list<T>来传入不定数量的形参:

void error_msg(initializer_list<string> il)
{
    for (auto beg = il.begin(); beg != il.end(); ++beg) {
        /* Do something */
    }
}

调用返回引用的函数得到一个左值

函数返回数组: auto func(int i) -> int(*)[10]; //c++11, 尾置返回类型

函数指针声明:

bool compare(const string&, const string&);
bool (*pf)(const string&, const string&);
pf = compare;
bool b1 = pf("hello", "world");
void useFunc(const string& s1, const string& s2, bool pf(const string&, const string&));
useFunc("hello", "world", compare);
auto fl(int) -> int (*)(int*, int*);

编译器为类对象生成的四个默认函数:构造函数,析构函数,拷贝构造函数,赋值运算符

vector便于访问,list便于插入删除

向泛型算法中传递谓词

bool isShorter(const string& s1, const string& s2) {
    return s1.size() < s2.size();
}
sort(words.begin(), words.end(), isShorter);

lambda函数
[capture list](parameter list)->return type {function body}, 其中参数列表和返回类型可忽略

auto f = [] { return 42; };
stable_sort(words.begin(), words.end(), [](const string& s1, const string& s2){ return s1.size() < s2.size() });
size_t sz = 100;
auto fz = [sz](const string& s1){ return s1.size() < sz }; // 函数拷贝捕获列表里的值而不是引用。
auto fs = [=, &](const string& s2){ return s1.size() < sz; } // 隐式捕获,=值捕获,&引用捕获

map会自动排序,无序关联容器使用unordered_map。map的底层实现是红黑树或AVL树,unordered_map的底层实现是哈希表

使用make_pair(key, value)来快速创建pair

程序中的内存包括静态内存(存储static成员),栈内存(存储非static对象,会自动销毁),堆内存(存储动态分配的对象,即在程序运行时分配的对象,生命周期由程序控制)

动态内存(堆)需要通过new和delete进行申请和释放

shared_ptr允许多个指针指向一个对象,unique_ptr独占对象

shared_ptr<int> p = make_shared(42); //创建一个指向42的指针
auto p2 = make_shared(10, '1');

拷贝构造函数,拷贝赋值运算符

// Foo中有一个string指针ps和int成员变量i
Foo(const Foo& f) //一般形参为const引用
    : ps(*f.ps)
    , i(p.i) {}
Foo& operator= (const Foo&); //形参为const引用,返回引用(*this)
Foo& Foo::operator= (const Foo&rhs) {
    auto newp = new string(*rhs.ps); //分配新地址
    delete ps; //释放旧地址
    ps = newp;  //将数据拷贝到本对象
    i = rhs.i;
    return *this;  //返回本对象
}
Foo(const Foo&) = delete; //阻止拷贝
Foo& operator= (const Foo&) = delete; //阻止赋值

重载输入输出运算符(不能是类的成员函数)

ostream& operator<<(ostream& os, const Foo& item) {
    os << item.isbn() << " " << item.name();
    return os;
}
istream& operator>>(istream& is, Foo& item) {
    is >> item.bookNo >> item.name;
    return is;
}

算数运算符形参一般是常量引用

Foo operator+(const Foo& lhs, const Foo& rhs) {  //非成员函数
    Foo sum = lhs;
    sum += rhs;  //也需要重新定义+=运算符
    return sum;    
}
Foo& Foo::operator+=(const Foo& rhs) {  //成员函数
    a += rhs.a;
    return *this;
}
bool operator==(const Foo& lhs, const Foo& rhs) {  //非成员函数
    return lhs.a() == rhs.a() && lhs.b() == rhs.b();
}
string& Foo::operator[](size_t n) { return vec[n]; }  //成员函数,同时定义常量和非常量类型
const string& Foo::operator[](size_t n) { return vec[n]; }
Foo& Foo::operator++() { ++a; return *this; }  //前置++,成员函数,返回新值
Foo Foo::operator++(int) { Foo tmp = *this; ++*this; return tmp; }  //后置++,成员函数,int形参,内部使用前置++实现,返回原值

基类的析构函数一般定义为虚函数,虚函数可能会在运行时才被解析

final关键字表示该类不能被继承,或是某函数不能被覆盖

模板,函数模板可以推断类型,但类模板必须显式指出类型

template <typename T> T foo(T* p) {
    T tmp = *p;
    // ...
    return tmp;
}
int i = 42;
int* p = &i;
i = foo(p);
template <typename T, typename U>
template <unsigned U> // 非类型参数模板
template <typename T> class Blob {} // 成员函数前也要加template关键字
Blob<int> prices;

explicit关键字用来防止单参数构造函数定义的隐式转换

上一篇下一篇

猜你喜欢

热点阅读