1.新的、、、自由关系
对象的析构函数会被调用,new对应的free只会释放内存,new会调用构造函数。 和free是C++/C语言的标准库函数,new/是C++的运算符。
它们可用于申请动态内存和释放内存。 对于非内部数据类型的对象,单独使用maloc/free无法满足动态对象的要求。
对象在创建时必须自动执行构造函数,对象在消亡前必须自动执行析构函数。
由于/free是库函数而不是操作符,因此不在编译器的控制权限之内,不能将执行构造函数和析构函数的任务强加给/free。
因此,C++语言需要一个可以完成动态内存分配和初始化的 new,以及一个可以完成清理和释放内存的。 请注意,new/ 不是库函数。
2.与[]的区别
析构函数只会被调用一次,而[]会调用每个成员的析构函数。
More C++中有更详细的解释:“当对数组使用运算符时,它会为每个数组元素调用析构函数,然后调用释放内存。” 匹配新的,[]匹配新的[]
MemTest *mTest1 = new MemTest[10];
MemTest *mTest2 = new MemTest;
Int *pInt1 = new int [10];
Int *pInt2 = new int;
delete[]pInt1; //-1-
delete[]pInt2; //-2-
delete[]mTest1;//-3-
delete[]mTest2;//-4-
在-4-处报告错误。
这意味着:对于内置的简单数据类型,[]的功能是相同的。
对于自定义复杂数据类型,[] 不能互换使用。 [] 删除数组,删除指针。
简单来说就是删除new分配的内存; 用new[]分配的内存用[]删除。 [] 将调用数组元素的析构函数。
内在数据类型没有析构函数,所以这没什么大不了的。 如果不带括号使用它,它会认为它指向单个对象,否则,它会认为它指向一个数组。
3、C++有哪些特性(面向对象的特性)
封装、继承和多态。
4、子类析构时是否应该调用父类的析构函数?
析构函数的调用顺序是先析构派生类,再析构基类,也就是说,当调用基类的析构函数时,派生类的所有信息都已经被销毁了。
定义对象时,先调用基类的构造函数,然后调用派生类的构造函数; 析构时则正好相反:先调用派生类的析构函数,然后调用基类的析构函数。
5.多态、虚函数、纯虚函数
多态性:不同的对象收到相同的消息时会产生不同的动作。 C++的多态性体现在运行和编译两个方面:程序运行时的多态性通过继承和虚函数体现;
多态性体现在程序编译时函数和运算符的重载;
虚函数:基类中用关键字标记的成员函数。 它提供了一个接口接口。 允许在派生类中重新定义基类虚函数。
纯虚函数的作用:在基类中为其派生类保留一个函数名,以便派生类可以根据需要进行定义。 纯虚函数作为接口,不具备函数的功能,一般不能直接调用。
从基类继承的纯虚函数在派生类中仍然是虚函数。 如果一个类至少有一个纯虚函数,那么这个类就称为抽象类(class)。
抽象类不仅包括纯虚函数,还包括虚函数。 抽象类必须用作派生其他类的基类,并且不能用于直接创建对象实例。 然而,使用抽象类的指针仍然支持运行时多态性。
6.找到以下函数的返回值()
int func(x) {
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
假设 x = 9999。答案:8
思路:将x转成二进制,看其中包含的1的个数。
7. 什么是“参考”? 声明和使用“引用”时应注意哪些问题?
答:引用是目标变量的“别名”(别名),对应用程序的操作与直接对变量的操作完全相同。
声明引用时,请记住对其进行初始化。
声明引用后,意味着目标变量名有两个名称,即目标的原始名称和引用名,并且引用名不能用作其他变量名的别名。
声明引用并没有定义一个新的变量,它仅仅意味着引用名是目标变量名的别名,它本身并不是数据类型,所以引用本身不占用存储单元,系统也不会占用存储单元。分配存储单元以供参考。 无法创建对数组的引用。
8、使用“”作为函数参数有什么特点?
(1) 传递函数的引用与传递指针具有相同的效果。
此时,被调用函数的形参作为原调用函数中实参变量或对象的别名,因此被调用函数中对形参变量的操作就是对应的目标对象(在main中)调用函数)调用函数)操作。
(2)函数的参数采用引用传递,在内存中不生成实参的副本,直接对实参进行操作; 而函数的参数是通过一般变量传递的,当函数调用发生时,需要分配存储给形参单元,形参变量是实参变量的副本;
如果传递一个对象,复制构造函数也会被调用。 因此,当参数传递的数据较大时,引用的效率和占用的空间都比一般变量要好。
(3)虽然使用指针作为函数参数也可以达到使用引用的效果,但是在被调用的函数中,还必须给形参分配存储单元,并以“*指针变量名”的形式进行操作” 需要重复。 这样容易出错,程序的可读性较差; 另一方面,在调用函数的调用点,必须使用变量的地址作为实参。 另一方面,参考文献更易于使用且更清晰。
9. 什么时候需要使用“常量引用”?
如果你想使用引用来提高程序的效率,并保护传递给函数的数据不被在函数中改变,那么你应该使用常量引用。
常量引用声明方法:const类型标识符&引用名=目标变量名;
portant;overflow-wrap: inherit !important;word-break: inherit !important;">例1
int a;
const int &ra=a;
ra=1; //错误
a=1; //正确
例2
string foo( );
void bar(string & s);
那么下面的表达式就是非法的:
bar(foo( ));
bar("hello world");
原因是 foo() 和“hello world”字符串都会生成一个临时对象,而在 C++ 中,这些临时对象是 const 类型。
所以上面的表达式试图将 const 类型的对象转换为非 const 类型,这是非法的。 如果引用参数可以定义为const,则应尽可能定义为const。
10. 使用“引用”作为函数的返回值类型时的格式、好处和要遵循的规则是什么?
格式:类型标识符&函数名(形参列表和类型描述){ //函数体}
好处:内存中没有返回值的副本; (注:正是因为这个原因,不建议返回局部变量的引用。因为随着局部变量的生命周期结束,相应的引用也会失效,产生错误!
防范措施:
(1) 无法返回对局部变量的引用。 本文可以参考C++[1]的Item 31。 主要原因是函数返回后局部变量会被销毁,因此返回的引用变成了“无”引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用。 本文可以参考C++[1]的Item 31。 虽然不存在被动销毁局部变量的问题,但是对于这种情况(返回函数内部new分配的内存的引用),却面临着其他尴尬的情况。 例如,函数返回的引用只以临时变量的形式出现,而没有被分配实际的变量,那么该引用指向的空间(由new分配的)就无法释放,造成泄漏。
(3) 可以返回对类成员的引用,但最好是const。 这个原理可以参考C++[1]的Item 30。 主要原因是,当一个对象的属性与某个业务规则(规则)关联时,其赋值往往与该对象的一些其他属性或状态相关,因此需要将赋值操作封装在业务规则中。 如果其他对象可以获得对该属性的非常量引用(或指针),那么仅仅对该属性进行赋值就会破坏业务规则的完整性。
(4) 流运算符重载的返回值被声明为“引用”:
流运算符,这两个运算符常常被期望连续使用,例如:cout