1.new、delete、malloc、free之间的关系 malloc和free都是C/C++标准库函数。new/delete是运算符。 都是用于动态申请和释放内存。 new会调用对象的构造函数,delete调用对象的析构函数,而malloc和free只能申请和释放内存。 由于 malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加给 malloc/free。
2.delete和delete []的区别 delete 只会调用一次析构函数,而 delete[] 会调用每一个成员函数的析构函数。 delete[]删除一个数组,delete删除一个指针。简单来说,用new分配的内存用delete删除;用new[]分配的内存用delete[]删除。
3.C++有哪些性质(面向对象特点) 封装、继承和多态
4.子类析构时要调用父类的析构函数吗? 析构函数调用的次序是先子类的析构后父类的析构;定义一对象时先调用父类的构造函数然后在调用子类的构造函数
5.介绍多态、虚函数和纯虚函数。 多态:对于不同对象接受相同信息时产生的不同动作;例如,对于三角形和矩形而言,计算各自的面积的公式不一样,都是调用相同的方法(动态多态)。 多态分为两类:静态多态(静态多态的函数地址早绑定 - 编译阶段确定函数地址):函数重载和运算符重载属于静态多态,复用函数名;动态多态(动态多态的函数地址晚绑定 - 运行阶段确定函数地址):派生类和虚函数实现运行时多态
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
shape = &rec;
shape->area();
shape = &tri;
shape->area();
return 0;
}
虚函数:在基类中冠以关键字virtual的成员函数、它提供了一种接口界面,允许在派生类中对基类的虚函数重新定义 纯虚函数:在基类中为其派生类保留一个函数的名字,以便派生类在需要时对它进行定义。作为借口而存在的纯虚函数不具备函数的功能,一般不能直接调用(没实现)。从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类称为抽象类,抽象类是必须作为派生其他类的基类,而不能直接创造对象实例。
6.求下面函数的返回值(微软)
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
& 按位与如果两个相应的二进制位都为1,则该位的结果值为1,否则为0,也是二进制与全1为1,好那我们先把9999转化为二进制数:10011100001111 如x最后一位是1,则x-1最后一位变为0,前面不变,而1 & 0 = 0,所以最后一位的1变为了0 也就是10011100001111 & 10011100001110 = 10011100001110 此时最后一位为0 再减1 10011100001101 也就是10011100001110 & 10011100001101 = 10011100001100 每次相应于影响了最后一个带1的数前面保持不变 直到 x 为0 为止 该函数计算参数x的二进制中1的个数 8 次
7.什么是“引用”?声明和使用“引用”要注意哪些问题? 引用变量是一个别名,他是某个已存在变量的另一个名字。引用声明完毕后,相当于目标变量有两个名称,即该目标原名称是引用名,并且不能再将该引用名作为其他变量的别名。
8.将“引用”作为函数参数有哪些特点? (1)引用是对目标变量的别名,被调函数函数的形参被当做主调函数实参的一个别名来使用,所以在被调函数对形参的操作实际上是对目标对象的操作。 (2)使用引用传递参数,在内存中没有产生实参的副本,他是直接对实参操作;而使用一般变量传递参数时需要给形参分配存储单元,此时的形参变量时实参的一个副本。 (3)引用容易使用,更清晰, 引用相对于指针来说具有更好的可读性和实用性
9.在什么时候需要使用“常引用”? 既要提高程序的效率,又要保护传递给函数的数据不在函数中被改变。
10.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 好处:在内存中不产生被返回值的副本; ①不能返回局部变量的引用,主要原因是局部变量会在函数返回后被销毁,因此返回的引用就成为了“无所指”的引用,程序进入未知状态。 ②不能返回函数内部new分配的内存的引用,虽然不存在局部变量被销毁问题,但是因为被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际变量,那么这个这个引用所指向的空间就无法释放,造成内存泄漏。
11.结构与联合有何区别? ①结构体和联合体都是由多个不同的数据类型成员组成,但在任何一时刻,联合体中只存放了一个被选中的成员(所有成员公用一块地址空间),而结构体的所有成员都存在(不同成员的存放地址不同)。 ②对于联合体的不同成员赋值,将会对其他成员重写。原来的成员的值就不存在了,而对于结构体不同成员赋值是互不影响的。
12.重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别? 重载:允许存在多个同名函数,而这些函数的参数不同(或许参数个数不同,或许参数类型不同,或许两者都不同); 重写:子类重新定义父类虚函数。
13.分别写出bool,int,float,指针类型的变量a 与“零”的比较语句
if(!a){}
if(0==a){}
if(NULL==a){}
const float EPSINON = 0.000001;
if(a<EPSINON && a>(-EPSINON )){}
14.请说出const与#define相比,有何优点? const作用:定义常量、修饰函数函数、修饰函数返回值三个作用。被const修饰后受到强制保护,可以预防意外的变动,能提高程序的健壮性。 1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
|