1多态性都有哪些?(静态和动态,然后分别叙述了一下虚函数和函数重载)
静态多态:编译时多态 模板编程T a,T b 输入a的类型不同,则运行结果不同
动态多台:运行时多态 由虚函数实现,派生类重写基类的成员函数,达到多态。
在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。这里的多态性是指类的多态性。
2虚函数,纯虚函数、抽象类
虚函数:必须实现 virtual
虚函数的工作原理:通常,编译器处理虚函数的方法是:给每一个对象添加一个隐藏成员.隐藏成员中保存了一个指向函数地址数组的指针.这种数组称为虚函数表(virtual function table, vtbl).虚函数表中存储了为类对象进行声明的虚函数的地址.例如,基类对象包含一个指针,访指针指向基类中所有虚函数地址表.派生类对象将包含一个指向独立地址表的指针.如果派生类提供了虚岁函数的新定义,访虚函数表将保存新函数的地址;如果派生类没有重新定义虚函数.该vtbl将保存函数原始版本的地址.如果派生类定义了新的虚函数,则该函数的地址也将被添加到vtbl中.注意,无论类中包含的虚函数是1还是10 个,都只需要在对象中添加1个地址成员,只是表的大小不同而已.
纯虚函数:纯虚函数在基类中不实现,在派生类中进行实现。virtual int a ( ) =0 ;它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。
抽象类:抽象类是指包括至少一个纯虚函数的类。
3动态绑定
虚函数是类的成员,是所有的对象所共有的,因此要特殊保存虚函数也应该是类的事情,而不是对象的事情,对象只要能够找到它们就可以了。
是这样设计的,编译起会为每个有虚函数的类都创建一个虚函数表,里面记录着每个虚函数。另外,每个对象有一个隐含指针指向它对应的类的虚函数表。
动态绑定的调用过程是这样的,首先,基类指针被赋值为派生类对象的地址,那么就可以找到指向这个类的虚函数的隐含指针,然后通过该虚函数的名字就可以在这个虚函数表中找到对应的虚函数的地址。然后进行调用就可以了。
4操作符重载(+操作符),具体如何去定义,?(让把操作符重载函数原型说一遍)
重载操作符就是让操作符作用域非内置类型时也有自己独特的意义。
class person{
private:
int age;
public:
person(int a){
this->age=a;
}
inline bool operator == (const person &ps) const;
friend bool operator == (const person &ps1,const person &ps2);
};
实现方式如下:
inline bool person::operator==(const person &ps) const
{
if (this->age==ps.age)
return true;
return false;
}
友元函数实现的话没有this指针,就会有两个参数
bool operator ==(const person &ps1,const person &ps2)
{
return operator()
}
5内存对齐的原则?(原则叙述了一下并举例说明) #pragma pack(x) 自定义对齐
1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.
typedef struct bb
{
int id; //0-3
double weight; //[8].....[15] 原则1
float height; //[16]..[19],总长要为8的整数倍,补齐[20]...[23] 原则3
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
int id; //[4]...[7] 原则1
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47] 原则2
}AA;
int main()
{
AA a;
cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
return 0;
}
6模版怎么实现
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。
例如swap函数,但是不同的类型 int float double都得重新写一遍
可以:
template<typename T>
void swap(T &a,T &b)
{
T t;
t = a;
a = b;
b = t;
}
这样输入不一样的值就自动转换了。
7指针和const的用法?(谁在前面谁不能变,俩const包*的话都不能变)
const int *p; 常量指针 变量值不能改变
int *const p; 指针常量 指针值不能改变
const int *const ptr; 两个const的是值和指针都不能改变
int const *const ptr;
8为什么基类的析构函数要定义成析构函数?
意思是不是虚函数的话,在进行析构的时候会调用基类的析构函数,而不是派生类的析构函数,会造成内存泄漏。
9内联函数、宏定义(提高函数的执行效率,适用于小并且用的频率高的函数)
内联函数:在定义前加上inline,在申明前加没用哦!
优点:提高执行效率(调用函数花费大于函数处理)
缺点:代码过长不适合
复杂的函数不适合
inline int max (int a,int b) //只有都在申明前有没用的!!!
inline int max(int a, int b)
{
return a > b ? a : b;
}
———————————————————————————————————————————
宏定义缺点:1容易出错,在预处理会产生边际效应
2 不可调试
#define MAX(a,b) (a) > (b) ? (a):(b) !!! 注意括号
10 const typedef #define(主要讲了const的用处,有那些优点)
const:可以指定类型,进行类型检测 会分配空间,可以调用 ,他是在运行才分配空间啥的,可以调试出来
typedef: 只是一个别名 不分配空间 typedef INT int
#define(#define #undef):无法对宏定义中的变量进行类型检查,它是在预编译前就搞好了,出错了也不知道
11 extern ,static
extern + 函数/变量 ==该函数或者变量是全局的
static :相反,只能在本模块中用
12 排序算法大集合
排序法 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) |
快速排序 | O(n2) | O(n*log2n) | 不稳定 | O(log2n)~O(n) |
选择排序 | O(n2) | O(n2) | 稳定 | O(1) |
二叉树排序 | O(n2) | O(n*log2n) | 不一顶 | O(n) |
插入排序 | O(n2) | O(n2) | 稳定 | O(1) |
堆排序 | O(n*log2n) | O(n*log2n) | 不稳定 | O(1) |
希尔排序 | O | O | 不稳定 | O(1) |
void quickSort(int s[], int l, int r) //快排
{
if (l< r)
{
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j]>= x) // 从右向左找第一个小于x的数
j--;
if(i < j && s[j] < x)
s[i++] = s[j];
while(i < j && s[i]< x) // 从左向右找第一个大于等于x的数
i++;
if(i < j && s[i] >= x)
s[j--] = s[i];
}
s[i] = x;
quickSort(s, l, i - 1); // 递归调用
quickSort(s, i + 1, r);
}
}
void quickSort(int a[],int r, int l)
{
if(r < l)
{
int i = l , j = l , x = s[l];
while(i < j)
{
while(i < j && s[j] >= x)
j --;
if(i < j && s[j]<x)
s[i++] = s[j];
while(i < j && s[i] <= x)
i++;
if(i < j && s[i]>=x)
s[j--] = s[i];
}
s[i] = x;
quickSort(s,l,i-1);
quickSort(s,i+1,r);
}
}
void bubble(int *pdata,int length)
{
for(int i = 0 ;i < length;i++)
{
for(int j = 0; j < length -i - 1;j++)
{
if(pdata[j]>data[j+1])
swap(pdata[j],pdata[j+1]);
}
}
}