电子说
这两期讲完基本上面试遇到的相关问题就过了一半了,后续将STL和内存相关的补充完整,C++这块的基本上就全部结束了,以后可能再也不会像现在这样在这个方向投入过多时间,且行且珍惜啊,还是跟以前一样,所有的总结都会有PDF版,如有需要自取。废话不多说,发完这期,继续整理STL去了。
1、C++函数模板
2、泛型算法
3、拷贝赋值和移动赋值
4、虚函数、静态绑定、动态绑定
虚函数表位于只读数据段(.rodata) ,也就是C++内存模型中的常量区;而 虚函数则位于代码段(.text) ,也就是C++内存模型中的代码区。
一个类添加了虚函数,对这个类有什么影响?
静态绑定和动态绑定:绑定指的是函数调用
覆盖:基类和派生类的方法,返回值、函数名以及参数列表都相同,而且基类的方法是虚函数,那么派生类的方法就是自动处理成虚函数,他们之间成为覆盖关系。
在类内部添加一个虚拟函数表指针,该指针指向一个虚拟函数表,该虚拟函数表包含了所有的虚拟函数的入口地址,每个类的虚拟函数表都不一样,在运行阶段可以循环脉络找到自己的函数入口。纯虚函数相当于占位符,现在虚函数占一个位置由派生类实现后再把真正的函数指针填进去。
5、虚析构函数
虚函数依赖:
构造函数:没有虚构造函数!!!
派生类对象构造过程:先调用的是基类的构造函数,才调用派生类的构造函数。
static静态成员方法 NO!
基类的指针(引用)指向堆上new出来的派生来对象的时候,delete pb(基类指针),它调用析构函数的时候,必须发生动态绑定,否则会导致派生类的析构函数无法调用
问题:是不是虚函数的调用一定就是动态绑定?肯定不是!
在类的构造函数当中,调用虚函数,也是静态绑定(构造函数中调用其他函数(虚),不会发生动态绑定)
静态绑定 用对象本身调用虚函数,是静态绑定
动态绑定:
6、如何解释多态
静态(编译时期)的多态:函数重载、模板(函数模板和类模板)
bool compare(int , int) { }
bool cpmpare(double, double) { }
compare(10,20); call compare_int_int 在编译阶段就确定好调用的函数版本
compare(10.5, 20.5); call compare_double_double 在编译阶段就确定好调用的函数版本
template<typename T>
bool compare(T a, T b) { }
compare<int>(10,20); => int 实例化一个compare<int>
compare(10.5 ,20.5); => double 实例化一个 compare<double>
动态(运行时期)的多态:
在继承结构中,基类指针(引用)指向派生类对象,通过指针(引用)调用同名覆盖方法(虚函数),基类指针指向哪个派生类对象,就会调用哪个派生类对象的同名覆盖方法,称为多态。
pbase->show();
多态底层是通过动态绑定来实现的,pbase->访问谁的vfptr ->继续访问谁的vftable -> 当然调用的是对应的派生类对象的方法了。
7、继承
广义的继承有三种实现形式:
好处:
8、抽象类和普通类的区别
一般把什么类设计成抽象类?基类
//动物的基类 泛指 类 -> 抽象一个实体的类型
定义Animal的初衷,并不是让Animal抽象某个实体的类型
拥有纯虚函数的类,叫抽象类!(Animal)
Animal a; NO!!!
抽象类不能再实例化对象了,但是可以定义指针和引用变量。
class Animal
{
public:
Animal(string name) : _name(name) { }
virtual void bark() = 0; //纯虚函数
protected:
string _name;
};
//以下是动物实体类
class Cat : public Animal
{
public:
Cat(string name) : Animal(name) { }
void bark() { cout << _name << "bark: miao miao!" << endl; }
};
class Dog :public Animal
{
public:
Dog(string name):Animal(name) { }
void bark() { cout << _name << "bark: wang wang!" << endl; }
};
class Pig :public Animal
{
Pig(string name) :Animal(name) { }
void bark() { cout << _name << "bark: heng heng! " << endl; }
};
void bark(Animal* p)
{
p->bark(); //Animal::bark虚函数,动态绑定了
}
int main()
{
Cat cat("猫咪");
Dog dog("二哈");
Pig pig("佩奇");
bark(&cat);
bark(&dog);
bark(&pig);
return 0;
}
9、抽象类(有纯虚函数的类) / 虚基类
virtual
class A
{
public:
virtual void func() { cout << "call A::func" << endl; }
void operator delete(void* ptr)
{
cout << "operator delete p:" << ptr << endl;
free(ptr);
}
private:
int ma;
};
class B :virtual public A
{
public:
void func() { cout << "call B::func" << endl; }
void* operator new(size_t size)
{
void* p = malloc(size);
cout << "operator new p:" << p << endl;
return p;
}
private:
int mb;
};
A a; 4个字节
B b; ma,mb 8个字节
int main()
{
B b;
A* p = &b;
cout << "main p:" << p << endl;
p->func();
return 0;
}
基类指针指向派生类对象,永远指向的是派生类基类部分数据的起始地址。
10、C++多继承
菱形继承的问题:派生类有多份间接基类的数据, 设计的问题
使用虚继承
好处 :可以做更多代码的复用。
C++语言级别提供的四种类型转换方式:
11、函数对象
把有operator() 小括号运算符重载函数的对象,称作函数对象或者仿函数。
//函数对象
template
12、菱形继承
多重继承-菱形继承的问题:
基类被多个派生类用就需要是虚继承,不然就会报错。
基类需要被最后的派生类初始化。
全部0条评论
快来发表一下你的评论吧 !