国信网络模版网站建设方案相关,便宜的游戏服务器租用,益阳住房和城乡建设局网站,做下载类网站一年赚多少钱C面试题
1 菱形继承
2 多态
多态实现原理#xff1a; 静态多态 动态多态 静态多态#xff1a; 依赖函数重载#xff0c;编译期确定。 函数重载#xff1a;允许在同一作用于内声明多个功能类似的同名函数#xff0c;函数列表不同。注意#xff1a;不能仅通过返回值类型…C面试题
1 菱形继承
2 多态
多态实现原理 静态多态 动态多态 静态多态 依赖函数重载编译期确定。 函数重载允许在同一作用于内声明多个功能类似的同名函数函数列表不同。注意不能仅通过返回值类型确定重载函数模板也是其中之一。 原理1 函数名修饰2 编译过程预编译 把头文件当中的函数声明拷贝到源文件避免编译过程中的语法分析找不到函数定义* 编译 语法分析同时进行符号汇总函数名* 汇编 生成函数名到函数地址的映射方便通过函数名找到函数定义位置链接 将多个文件中的符号表汇总合并objdump -t *.o // _Zn 类长度 类名 函数名长度 函数名 E 类型首字母动态多态 虚函数重写运行期确定 在基类的函数名前加virtual关键字在子类中重写 override 运行时将根据对象的类型调用相应的函数 如果对象的类型是基类则调用基类函数反之若是派生类则调用派生类函数
原理早绑定编译期已确定对象调用的函数地址晚绑定若类使用virtual函数则会为类生成虚函数表一维数组存放虚函数地址类对象构造时会初始化该虚表指针虚函数表指针在构造时初始化3 override/final
c11引入这两个关键字
原因 虚函数重写 不能阻止某个虚函数进一步重写 本意写一个心函数错误重写基类虚函数子类中virtual关键字可省略 本意重写基类虚函数但是签名不一致在子类中重新构建了一个新的虚函数
类继承不能阻止某个类进一步派生override 指定子类一个虚函数复写基类的一个虚函数 保证该重写的虚函数与基类的虚函数具有相同的签名
final 指定某个虚函数不能在派生类中被覆盖或者某个类不能被派生 阻止类进一步派生 阻止虚函数进一步重写
4 类型推导
类型 模板方法中模板参数类型的推导 auto decltype (都是c11引入其中auto的类型推导是c引入)
原因 c是强类型语言 编译器来处理类型推导 提升语言的编码效率
关键字 auto 原理用于推导变量的类型通过强制声明一个变量的初始值编译器会通过初始值进行推导类型。 规则变量必须在定义时初始化如果用auto定义多个变量那么这些变量必须为同一类型类型推导时会丢失cv语义/; 需要保留/cv,使用const / const auto 万能引用 auto, 根据初始值的属性来判断左值引用/右值引用 auto不能推导数组类型会得到指针类型 auto可以推导函数返回值类型c14 应用尽量使用auto声明变量除非影响到可读性使用容器时名字较长使用auto更方便匿名函数返回值模板函数中可以节约模板参数类型延伸typeid会丢失顶层consttypeid只有在虚表查找时才会有运行时开销否则都是在编译阶段完成decltype原理用于推导表达式的类型只分析表达式类型而不参与运算规则exp是普通表达式推导表达式类型exp是函数调用推导函数返回值类型exp是左值引用推导出左值引用应用范型编程5 function/lambda/bind
function 类模板 一个抽象了函数参数以及函数返回值的类模板 抽象方式将任意函数包装成一个对象该对象可以保存/传递/复制动态绑定只需要修改该对象赋值不同的function对象实现类似多态的效果用途保存普通函数类的静态成员数据保存仿函数保存类成员函数保存lambda表达式functionvoid(CHello *, int) f CHello::hello;仿函数函数对象 重载了操作符’()的类
class Hello {void operator()(int count) {i count;cout Hello i endl;}int i;
};
functionvoid(int) f Hello();
f(3);特征可以有状态通过成员变量进行存储有状态的函数对象成为闭包lambda表达式 一种方便创建匿名函数对象的语法糖 int i 0;// auto f_hello [i]() mutable - void { i; cout lambda i: i endl;}; // 未修改外部变量闭包auto f_hello [i]() { i; cout lambda i: i endl;}; // 修改外部变量f_hello();f_hello();cout global i: i endl;构成捕获列表[]值捕获默认只读不能修改mutable可读可写并不会修改外部变量的值引用捕获可读可写修改外部变量的值本质外部变量将转变为类的成员变量参数列表()指定返回值-可省略因为有类型推导函数体{}原理编译时将lambda表达式转变为一个函数对象根据lambda参数列表重载operator()bind 用来通过绑定函数以及函数参数的方式生成函数对象的模板函数 提供占位符实现灵活的绑定
特征:绑定函数以及函数参数 构成一个函数对象闭包允许修改参数顺序部分参数可设置固定值丢弃多余参数auto f_bind bind(bind_func, 1, 2); // 函数名取地址auto f_class_func bind(CHello::hello, obj, 1000);auto f_placement bind(CHello::hello, obj, placeholders::_1);总结 lambda和bind生成一个函数对象 function用来描述函数对象的类型 lambda用来生成匿名函数即函数对象可以访问外部变量的匿名函数 bind也是用来生成函数对象函数和参数进行绑定生成函数对象
6 继承下的构造函数和析构函数执行顺序
继承下构造函数依照依赖链从上往下构造析构函数从下向上析构
单继承 成员类按照顺序构造按相反顺序析构 类的构造依赖成员类的构造基类比成员类依赖性更强
多继承 成员类按照顺序构造按相反顺序析构 类的构造依赖成员类的构造基类比成员类依赖性更强 多继承中基类按声明顺序构造按相反顺序析构
7 虚函数表和虚函数表指针的创建时机
虚函数表的创建时机 编译器发现类中包含virtual关键字修饰的函数虚函数表的内容在编译期已经生成.o文件 存放于全局数据区只读数据段 虚函数表中存放虚函数的地址的数组
虚函数表指针的创建时机 对象构造时在构造函数中将虚函数表的地址赋值给对象vptr 如果没有构造函数则编译器为类生成默认构造函数为类对象初始化vptr 继承下虚函数表指针赋值过程先是基类赋值再是子类赋值覆盖行为
8 虚析构函数作用
在继承下为了使子类析构函数能够得到正常调用需要将基类的析构函数设置为虚析构函数
使用场景 子类对喜爱嗯指针赋值给基类指针在调用析构函数时子类对象的析构函数得不到调用
设计原因 在c看来我们设计某个类不一定是基类如果是基类应该手动将基类的析构函数设置为虚函数 设置虚析构函数是有代价的编译器会为类生成虚函数表每个对象都需要持有vptr
9 面向对象三大特征
封装 目的隐藏实现细节实现模块化 特性 访问权限 public 对所有对象开放 protected 对子类开放 private 只对自己开放使用友元类打破private权限
继承 目的无需修改原有类的情况下实现功能扩展 特性 权限继承 public继承 基类成员权限保持 protected继承 基类成员public/protected变为protected private继承 基类成员public/protected/private都变为private 使用using修改基类成员在子类中的权限比如在public中using data A::c;多继承接口继承纯虚函数多态 目的一个接口多种形态通过实现接口重用增强可扩展性 特性 静态多态 函数重载 动态多态 通过虚函数重写
10 动态库与静态库
动态库与静态库都是先生成.o文件
静态库编译
ar rcs target.a *.o # r:replace c:grade s:suchg -static main.cpp -o static_target -L./ -lapi -I./ # -lapi libapi.a动态库编译
g -shared -fPIC -o target.so *.og main.cpp -o dynamic_target -L./ -lapi -I./ # -lapi libapi.so静态编译产物 动态编译产物 # 动态编译未全部装载
动态编译依赖LD_LIBRARY_PATH
export LD_LIBRARY_PATH$LD_LIBRARY_PATH:[new_path]11 智能指针
指针管理的困境 资源释放了但指针未置空 指针悬挂 - 一个/多个指针指向同一资源 踩内存
未释放资源 内存泄漏重复释放资源coredump错误使用未初始化指针野指针解决方案 智能指针利用RAII思想自动化管理指针指向的动态资源的释放举例mutex mtx; mtx.lock(); mtx.unlock(); RAII利用对象的生命周期管理资源 智能指针利用构造/析构函数来管理资源
智能指针 shared_ptr 解决指针悬挂问题 语义共享所有权 资源无明确拥有者 原理引用计数由最后一个对象释放资源 场景 容器中管理指针 - vectorshared_ptrT vec; 资源通过函数传递 使用规范 使用shared_ptr管理动态资源时不要使用原来的裸指针 构造智能指针时不要暴露裸指针 尽量使用make_shared构造智能指针 不要使用int *p sp.get();; 不要使用一个指针构造多个智能指针对象 不要用类对象指针this作为shared_ptr返回 不能暴露裸指针
// 不推荐用法
int *p new int();
shared_ptrint sp shared_ptrint(p);// 不太推荐用法
shared_ptrint sp shared_ptrint(new int);// 推荐用法
shared_ptrint sp make_sharedint();// 不应该使用的方式
class T {
public:// 违反条款不应该使用一个指针构造多个智能指针对象shared_ptrT self() {return this; // return shared_ptrT(this); 也不应该使用}
};// 改进方案可用
class T : public enable_shared_from_thisT {
public:shared_ptrT self() {return shared_from_this();}
};weak_ptr辅助shared_ptr用来解决shared_ptr循环引用原因是弱引用不占用强引用类型class A {
public:~A() {cout A deconstructor endl;}// shared_ptrB spb; 问题写法weak_ptrB spb;
};class B {
public:~B() {cout B deconstructor endl;}// shared_ptrA spa; // 问题写法weak_ptrA spa;
};int main()
{// 循环引用shared_ptrA sp1 make_sharedA();shared_ptrB sp2 make_sharedB();sp1-spb sp2;sp2-spa sp1;cout A.use_count(): sp1.use_count() B.use_count(): sp2.use_count() endl;return 0;
}unique_ptr语义独享所有权没有拷贝语义仅提供移动语义明确某个对象只有一个拥有者场景使用规范不支持拷贝但可以从函数中返回一个unique_ptr - 编译器优化编译器优化关闭情况下如果有移动构造调用移动构造如果有拷贝构造调用拷贝构造没有拷贝构造返错make_unique (c14)// 可用
unique_ptrT get_unique() {unique_ptrT up;return up;
}12 c11用过的特性
考察思路 回答问题的层次 学习总结的思路
语法糖 关键字 auto / decltype nullptr 以往用NULL它是0int nullptr是一个具体的空指针会去匹配空指针类型的函数参数 final / override 在继承中 constexpr 让编译器协助求值
语法基于范围的for循环function函数对象bindlambda目的使代码更便捷/严谨让编译器做更多的工作stl容器 array forward_list unordered_map unordered_set
智能指针 shared_ptr weak_ptr unique_ptr
多线程 thread 可以传闭包 mutex / lock_guard 可能会休眠 condition_variable 可能会休眠 atomic 原子操作限定cpu/编译器不要对某些变量或操作做违反一致性的优化
右值引用 T 将亡值 移动语义 实现移动语义 std::move 实现完美转发 万能引用 T std::forward