总结
C++
1.构造函数可以是虚函数吗?析构函数可以是虚函数吗?为什么析构函数要定义为虚函数?
①从存储空间角度
虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。
问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,
无法找到vtable,所以构造函数不能是虚函数。
②从使用角度
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而
构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,
因此也就规定构造函数不能是虚函数。
析构函数可以为虚函数,当析构一个指向子类的父类指针时,编译器可以根据虚函数表寻找到子类的析构函数进行调用,从而正确释放子类对象的资源。
如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除指向子类的父类指针时,只会调用父类的析构函数而不调用子类析构函数,这样就会造成子类对象析构不完全造成内存泄漏。
2.构造函数或者析构函数中调用虚函数会怎样?
在构造函数中调用虚函数,由于当前对象还没有构造完成,此时调用的虚函数指向的是基类的函数实现方式。
在析构函数中调用虚函数,此时调用的是子类的函数实现方式。
3.声明和定义的区别?
- 声明是告诉编译器变量的类型和名字,不会为变量分配空间。
- 定义就是对这个变量和函数进行内存分配和初始化。需要分配空间,同一个变量可以被声明多次,但是只能被定义一次。
4.指针函数和函数指针?
指针函数
指针函数是 返回指针的函数 主体是函数,返回值是一个指针
基本声明形式:返回数据类型 + * + 函数名 + (变量类型1,…);
int* fun(int,int);
int * fun(int,int);
int *fun(int,int);
函数指针
函数指针是 指向函数的指针 主体是指针 指向的是一个函数的地址
基本声明形式:*返回数据类型 + (函数名) + (变量类型1,…);
注意 * 和函数名要用括号括起来,否则因为运算符的优先级原因就变成指针函数了
#include<stdio.h>
int add(int x,int y)
{
return x + y;
}
int (*fun) (int,int); //声明函数指针
int main()
{
fun = &add; //fun函数指针指向add函数
printf("%d ",fun(3,5)); //两种方法都可以
printf("%d",(*fun)(4,2));
return 0;
}
5.指针常量?常量指针?
(1)常量指针:也叫常指针,最后两个字是“指针”,代表这是一个指针,但指向的是一个常量,如下:
1. int a =0;
2. const int *p = &a;//不可以通过p改变a
(2)指针常量:后面两个字是“常量”,代表这是个常量,不过是指针类型的常量,
1. int a = 0;
2. int *const p = &a; //从后往前看,这是个指针常量,指向的a的值可以改变,但p本身不可改变
注意:如果从代码来区分常量指针指针常量,那么可以从后往前看const的位置,
1. const int *p = &a //从后往前看,const修饰的是*p,所以指针p指向的数值不可变
2. int *const p = &a; //从后往前看,const修饰的是p,所以指针p本身不可变
6.深拷贝与浅拷贝
简单的来说,浅拷贝是增加了一个指针,指向原来已经存在的内存。浅拷贝在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误。
而深拷贝是增加了一个指针,开辟了一块空间让指针指向这块新开辟的空间。深拷贝和浅拷贝的不同之处,仅仅在于修改了下拷贝构造函数,以及赋值运算符的重载。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
7.什么时候需要自定义拷贝构造函数?
当数据成员中有指针时,必须要用深拷贝。
答:默认拷贝构造函数执行的是浅拷贝,对于凡是包含动态分配成员或包含指针成员的类都应该提供拷贝构造函数;在提供拷贝构造函数的同时,还应该考虑重载"="赋值操作符号。