重载new和delete后调用构造函数和析构函数顺序
C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容⼀、本⽂⽬的与说明1. 本⽂⽬的:理清在各种继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容。
2. 说明:虽然复制构造函数属于构造函数的⼀种,有共同的地⽅,但是也具有⼀定的特殊性,所以在总结它的性质时将它单独列出来了。
3. 单继承、多继承、虚继承,既然都属于继承,那么虽然有⼀定的区别,但还是相同点⽐较多。
如果放在⼀块讲,但为了将内容制作成递进的,就分开了,对相同点进⾏重复,(⼤量的复制粘贴哈),但在不同点进⾏了标注。
注意:三块内容是逐步递进的如果你懂虚函数,那么单继承和多继承那块你就可以不看;如果你懂多继承,那单继承你就不要看了,⾄于虚继承就等你懂虚继承再回来看吧;如果你只懂单继承,那你就只看单继承就好。
⼆、基本知识1. 对于⼀个空类,例如:class EmptyClass{};虽然你没有声明任何函数,但是编译器会⾃动为你提供上⾯这四个⽅法。
class EmptyClass {public:EmptyClass(); // 默认构造函数EmptyClass(const EmptyClass &rhs); // 复制构造函数~EmptyClass(); // 析构函数EmptyClass& operator=(const EmptyClass &rhs); // 赋值运算符}对于这四个⽅法的任何⼀个,你的类如果没有声明,那么编译器就会⾃动为你对应的提供⼀个默认的(注意合成默认构造函数是⽤于没有编写构造函数编译器才会合成默认构造函数,其中复制构造函数也是构造函数)。
(在《C++ primer》中,这个编译器⾃动提供的版本叫做“合成的***”,例如合成的复制构造函数)当然如果你显式声明了,编译器就不会再提供相应的⽅法。
2. 合成的默认构造函数执⾏内容:如果有⽗类,就先调⽤⽗类的默认构造函数。
C++面向对象程序设计考试试卷(详细讲解)(1)
C++面向对象程序设计考试试卷(详细讲解)(1)C++面向对象程序设计考试试卷(详细讲解)一、单项选择题(共20题,每题1分,共20分)1、下列关于C++标识符的命名不合法的是 C 与C#一样A. PadB. name_1C. A#bcD. _a122、若有以下类型标识符定义:()Dint x=2; char w='a'; float y=23.45f; double z=45.6712;则表达式w*x+y-z的结果类型是A. floatB. charC. intD. double6、对重载函数形参的描述中,错误的是 D 重载是重点A. 参数的个数可能不同B. 参数的类型可能不同C. 参数的顺序可能不同D. 参数的个数、类型、顺序都相同,只是函数的返回值类型不同7、以下能正确定义数组并正确赋初值的语句是 DA. int N=5,b[N][N];B. int a[2]={{1},{3},{4},{5}};C. int c[2][]={{1,2},{3,4}};D. int d[3][2]={{1,2},{3,4}};8、下列给字符数组进行的初始化中,不正确的是 DA. char s1[]="abcd";B. char s2[3]={'x','y','\0'};C. char s3[]={'a','x','y','\0'};D. char s4[6]={"xyz","mnp"};9、通常的拷贝构造函数的参数是 CA.某个对象名 B.某个对象成员名C.某个对象的引用 D.某个对象的指针名10、关于构造函数特点的描述中,错误的是 AA. 定义构造函数必须指出类型(构造函数特点是无返回类型)B. 构造函数的名字与该类的类名相同C. 一个类中可定义0至多个构造函数(不写构造函数,系统会自动生成一个空的构造函数)D. 构造函数是一种成员函数11、下面程序的运行结果为 C#includeint add(int a,int b);void main(){extern int x,y;cout<<add(x,y)<<endl;< p="">}int x=20,y=5;int add(int a,int b){int s=a+b;return s;}A.20 B.5 C.25 D.编译会提示出错信息12、关于常成员的描述中,错误的是 BA. 常成员包含常数据成员和常成员函数两种B. 常数据成员必须是公有的C. 常数据成员要使用构造函数成员初始化列表进行初始化D. 常对象只能调用它的常成员函数,不能调用其它的成员函数13、关于友元函数的描述中,错误的是 BA. 友元函数不是成员函数B. 友元函数只能访问类中私有成员C. 友元函数破坏隐藏性,尽量少用D. 友元函数说明在类体内,使用关键字friend14、如果有int x,*p; float y,*q;则下面操作正确的是 CA.p=x B.p=qC.p=&x D.p=&y16、若数组名作实参而指针变量作形参,函数调用时实参传给形参的是 DA. 数组的长度B. 数组第一个元素的值C. 数组所有元素的值D.数组第一个元素的地址17、对于动态分配内存空间描述正确的是 DA.使用new运算符分配的内存空间的长度必需是常量B.delete运算符可以释放动态的存储空间和静态的存储空间C.由new分配的内存空间是不连续的D.delete运算符只能释放由new分配的动态存储空间18、能够释放对象所占资源的是() AA.析构函数 B.数据成员C.构造函数 D.静态成员函数19、虚函数的定义是在基类中进行的,定义时需要冠以关键字 CA.static B.frendC.virtual D.public20、在C++中串流类是在头文件strstrea.h中定义的,下列不属于串流类的是) C A.strstream B.ostrstreamC.ofstream D.istrstream二、填空题(共9题16空,每空1分,共16分)1、函数重载时,编译系统会根据__形参的类型__ 或__形参的个数__ 来区分。
c++题库
假定AB 引用是某个变量的别名,对引用的操作就是对被引用变量的操作。
A. 对B. 错假定AB 为一个类,则执行AB x; 语句时将自动调用该类的无参构造函数。
A. 对B. 错构造函数用来初始化类的新对象,构造函数与类同名,返回类型只能为void。
A. 对B. 错用new动态分配的内存是在堆中分配的,而不是在栈中分配的。
—A. 对B. 错使用关键字class定义的类中缺省的访问权限是私有(private)的。
A. 对B. 错在公有继承中,基类中的公有成员和私有成员在派生类中都是可见的。
A. 对B. 错C++语言的标识符是不区分大小写的。
A. 对B. 错作用域运算符(::)只能用来限定成员函数所属的类。
A. 对B. 错》声明对象时,类名前面不需要加class关键字。
A. 对B. 错C++程序一般应当含有main函数,它是C++程序执行的入口。
A. 对B. 错可以在类的构造函数中对静态数据成员进行初始化。
A. 对B. 错C++语言中,既允许单继承,又允许多继承。
A. 对B. 错派生类的继承方式有两种:公有继承和私有继承。
…A. 对B. 错多继承情况下,派生类的构造函数的执行顺序取决于定义派生类时所指定的各基类的顺序。
A. 对B. 错类的私有成员只能被类中的成员函数访问,任何类以外的函数对它们的访问都是非法的。
A. 对B. 错构造函数和析构函数都不能重载。
A. 对B. 错在基类中被声明为虚函数的类的成员函数必须在每个派生类中显式声明为虚函数,才能具有多态的特征。
》A. 对B. 错关于运算符重载,运算符函数的返回类型不能声明为基本数据类型。
A. 对B. 错将类的一个对象赋值给该类的另一个对象时,调用拷贝构造函数。
A. 对B. 错模板可以使程序对任何数据类型进行同样方式的处理。
A. 对B. 错1. 编译源文件后产生的文件是()。
A. 目标文件B. 可执行文件C. 源文件D. 头文件>2. 每个C++程序只能有一个()。
C++new与delete
new和delete在C++中特别要重,在此简单总结一下new和delete各种含义。
new与operator newC++中有很多语法让人难以理解,如:new operator(操作符,下同)和operator new之间差异,确切的说,应该是new与operator new 的区别。
如下代码:string *ps=new string("memory management");这里所使用的new就是所谓new operator,是由C++语言内建的,就像sizeof那样,不能改变意义,总是做相同的事情。
这个动作的含义分为两方面:第一,它分配足够的内存,用来放置某类型的对象。
对于上例而言,它分配足够放置一个string 对象内存。
第二,它调用一个构造函数,为刚才分配的内存中的那个对象设定初始值。
new operator总是做这两件事,无论如何你是不能改变其行为。
能够改变的是用来容纳对象的那块内存的分配行为,new operator调用某个函数,执行必要的内存分配动作,你可以重写或者重载那个函数,改变其行为。
这个函数名称就叫operator new 。
开始晕了吧?函数operator new 通常声明如下:void * operator new (size_t size);其返回类型void*。
即返回一个指针,指向一块原始的、未设置初始值的内存。
函数中的size_t参数表示需要分配多少内存,你可以将operator new 重载,加上额外的参数,但第一个参数类型必须总是size_t。
或者你从来没有直接用过operator new .但是你可以调用任何其他函数一样地调用它。
void* rawMemory=operator new(sizeof(string));这里的operator new 将返回指针,它指几一块足够容纳string对象的内存。
和malloc一样,operator new 的唯一任务就是分配内存,它不知道什么是构造函数,它只负责分配内存。
new和delete的用法
new和delete的用法
new和delete用法
1、new和delete是C++中标准库规定的关键字之一,即动态内存分配
管理的操作符。
2、new用于在运行时分配内存空间并返回对象的首地址指针,delete
用于释放指定对象占用的内存空间。
3、new语法格式:指针变量= new 数据类型;
4、delete语法格式:delete 指针变量;
5、new和delete结合使用时,应当注意遵守C++定义的动态内存的匹
配原则,即要严格地按照一对new语句和一对delete语句的比例来使用。
6、new运算符可以在括号中指定空间大小,从而控制动态内存的长度:指针变量= new 数据类型[长度];
7、new和delete运算符在一起使用时,还可以用于分配和释放多维数组:
指针变量= new 数据类型[i][j];(i,j表示数组的维度)
delete [] 指针变量;
8、new运算符和delete运算符可以和成员函数一起使用:new对象后
调用对象中的成员函数,delete对象前调用成员函数释放相关资源。
9、new和delete运算符还可以用来实现复杂的内存申请和释放操作,
如关联内存的释放等。
10、在大量的程序中使用new和delete操作符,还需要注意异常处理,以保证程序的安全性。
c++期末考试判断题+填空题
判断题1、对空指针不能用delete运算符。
(错误)2、对重载的函数,要求函数类型相同但参数不同。
(错误)3、任何一个对象只能属于一个具体的类。
(正确)4、用new运算符来创建对象时不会调用构造函数。
(错误)5、对重载的函数,要求参数不同或函数类型不同。
(错误)6、在公有继承中,基类中的公有成员和私有成员在派生类中都是可见的。
(错误)7、析构函数可以是虚函数。
(正确)8、无论什么方式的继承,基类的私有成员都不能被派生类访问。
(正确)9、要达到动态联编的效果,基类和派生类的对应函数不仅名字相同,而且返回类型、参数个数和类型也必须相同。
(正确)10、如果派生类没有实现虚函数,那么它将使用他的基类的虚函数。
(正确)11、构造函数可以是虚函数。
(错误)12、指向对象数组的指针不一定必须指向数组的首指针。
(正确)13、对象数组的元素可以是不同类的对象。
(错误)14、对象数组可以赋初值又可以赋值。
(错误)15、一个类的构造函数可以不包含对其子对象的初始化。
(错误)16、在C++中,既允许单继承,又允许多继承。
(正确)17、派生类从基类派生出来,它不能生成新的派生类。
(错误)18、派生类的继承方式只有2种:公有继承和私有继承。
(错误)19、在公有继承中,基类的成员在派生类中都可以直接使用。
(错误)20、在单继承中,派生类中对基类成员的访问也会出现二义性。
(错误)21、解决多继承下二义性问题的方法之一是使用作用域运算符。
(正确)22、作用域运算符(::)只能用来限定成员函数所属的类。
(错误)注:还限制成员变量所属的类。
23、析构函数是一种函数体为空的成员函数。
(错误)24、构造函数和析构函数都不能重载。
(错误)注:构造函数可以重载,析构函数不可以重载(因为析构函数无参数,不可能进行参数区分)。
25、说明或定义对象时,类名前面不需要加class关键字。
(正确)26、对象成员的表示与结构变量成员表示相同,使用运算符.或->。
C++基础
C++基础1.new、delete、malloc、free关系delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。
malloc 与free是C++/C语言的标准库函数,new/delete是C++的运算符。
它们都可用于申请动态内存和释放内存。
对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。
对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。
注意new/delete不是库函数。
2.delete与delete []区别delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。
在More Effective C++中有更为详细的解释:―当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operatordelete来释放内存。
‖delete与New配套,delete []与new []配套MemTest*mTest1=newMemTest[10];MemTest*mTest2=newMemTest;int*pInt1=newint[10];int*pInt2=newint;delete[]pInt1; //-1-delete[]pInt2; //-2-delete[]mTest1;//-3-delete[]mTest2;//-4-在-4-处报错。
这就说明:对于内建简单数据类型,delete和delete[]功能是相同的。
对于自定义的复杂数据类型,delete和delete[]不能互用。
delete[]删除一个数组,delete删除一个指针简单来说,用new分配的内存用delete删除用new[]分配的内存用delete[] 删除delete[]会调用数组元素的析构函数。
详解C++中new运算符和delete运算符的使用
详解C++中new运算符和delete运算符的使⽤C++ ⽀持使⽤ new 和 delete 运算符动态分配和释放对象。
这些运算符为来⾃称为“⾃由存储”的池中的对象分配内存。
new 运算符调⽤特殊函数 operator new,delete 运算符调⽤特殊函数 operator delete。
在 Visual C++ .NET 2002 中,标准 C++ 库中的 new 功能将⽀持 C++ 标准中指定的⾏为,如果内存分配失败,则会引发std::bad_alloc 异常。
如果内存分配失败,C 运⾏库的 new 函数也将引发 std::bad_alloc 异常。
如果您仍需要 C 运⾏库的 new 的⾮引发版本,请将您的程序链接到 nothrownew.obj。
但是,当您链接到 nothrownew.obj 时,标准 C++ 库中的 new 将不再起作⽤。
调⽤ new 运算符在程序中遇到以下语句时,它将转换为对函数 operator new 的调⽤:char *pch = new char[BUFFER_SIZE];如果请求针对零字节存储,operator new 将返回⼀个指向不同的对象的指针(即对 operator new 的重复调⽤将返回不同的指针)。
如果分配请求没有⾜够的内存,则 operator new 将返回 NULL 或引发异常(有关详细信息,请参阅)。
可以编写尝试释放内存的例程并重试分配;有关详细信息,请参阅 _set_new_handler。
有关恢复⽅案的更多详细信息,请参阅以下主题:处理内存不⾜的情况。
下表中描述了 operator new 函数的两个范围。
operator new 函数的范围运算符范围::operator new全局class-name ::operator new类operator new 的第⼀个参数的类型必须为 size_t(STDDEF.H 中定义的类型),并且返回类型始终为 void *。
析构函数和构造函数调用顺序
析构函数和构造函数调用顺序构造函数和析构函数是面向对象编程中常用的两个概念,它们在对象的创建和销毁过程中起着重要的作用。
本文将分别介绍构造函数和析构函数的调用顺序。
一、构造函数的调用顺序构造函数是在对象创建时被调用的特殊成员函数,用于初始化对象的数据成员。
在创建对象时,编译器会自动调用构造函数。
1. 默认构造函数如果类没有定义任何构造函数,编译器会自动生成一个默认构造函数。
默认构造函数不接受任何参数,仅进行默认的初始化操作。
当创建对象时,会首先调用默认构造函数。
2. 带参数的构造函数如果类定义了带参数的构造函数,那么在创建对象时,可以通过传递参数来调用相应的构造函数。
如果定义了多个带参数的构造函数,编译器会根据实际传递的参数类型和个数来选择调用哪个构造函数。
3. 派生类构造函数调用顺序如果类是派生类,它的构造函数在创建对象时会先调用基类的构造函数,然后再调用自身的构造函数。
这是因为派生类的对象包含了基类的成员,所以需要先初始化基类的成员,再初始化自身的成员。
二、析构函数的调用顺序析构函数是在对象销毁时被调用的特殊成员函数,用于释放对象所占用的资源。
在对象销毁时,编译器会自动调用析构函数。
1. 默认析构函数如果类没有定义任何析构函数,编译器会自动生成一个默认析构函数。
默认析构函数不做任何操作。
当销毁对象时,会首先调用默认析构函数。
2. 派生类析构函数调用顺序如果类是派生类,它的析构函数在销毁对象时会先调用自身的析构函数,然后再调用基类的析构函数。
这是因为派生类的对象的成员在内存中的布局是先基类的成员,然后是自身的成员,所以需要先释放自身的成员,再释放基类的成员。
三、构造函数和析构函数的调用顺序总结1. 构造函数的调用顺序是先调用基类的构造函数,然后再调用派生类的构造函数。
2. 析构函数的调用顺序是先调用派生类的析构函数,然后再调用基类的析构函数。
3. 构造函数和析构函数的调用顺序与对象的创建和销毁顺序相反。
深入理解C语言的new[]和delete[]
深⼊理解C语⾔的new[]和delete[]⽬录1、重载操作符2、new和delete的原理3、new[]和delete[]的原理总结c++的动态内存管理⽅式和c语⾔不⼀样,在c++中使⽤new和delete来替换c语⾔中的malloc和free。
这⾥有⼏个点不⼀样,1、new和delete是操作符,malloc和free是函数(我的理解是c++将new和delete约定为操作符⽽已,new和delete操作符重载函数本质上还是函数)2、c++有了类的概念,类对象的初始化除了要分配内存,还需要对内存进⾏初始化!所以,c++必须引⼊⼀种新的内存分配⽅式,既可以像malloc⼀样开辟内存,还要能够调⽤类对象的构造函数(delete的引⼊同理)。
3、new[]和delete[]是c++完全新增的内存操作符,他们和new和delete也是有不⼀样的地⽅。
下⾯,咱们来⼀⼀讲解⬇1、重载操作符既然new和delete都是操作符,咱们可以对new和delete进⾏重载;当你再使⽤new和delete操作内存时,编译器就会调⽤到咱们⾃⼰重载的new/delete全局函数了。
(如对操作符重载不了解的,请⾃⾏补充知识)void* operator new(size_t size){if(size == 0) size = 1;void* ptr = malloc(size);if(ptr == nullptr){std::cout << "ERROR NEW!" << std::endl;}std::cout << "NEW Memory Size = " << size << " address = " << ptr << std::endl;return ptr;}void* operator new[](size_t size){if(size == 0) size = 1;void* ptr = malloc(size);if(ptr == nullptr){std::cout << "ERROR NEW[]!" << std::endl;}std::cout << "NEW[] Memory Size = " << size << " address = " << ptr << std::endl;return ptr;}void operator delete(void* ptr){std::cout << "DELETE " << ptr << std::endl;if(ptr) free(ptr);}void operator delete[](void* ptr){std::cout << "DELETE[] " << ptr << std::endl;if(ptr) free(ptr);}此时,再使⽤ int* p = new int {1}; 开辟内存,那么,c++编译器会⾃动链接到我们刚才的操作符重载函数 void*operator new(size_t size) ,⾄于编译器是怎么将 int* p = new int {1}; 解析成 void* operator new(size_t size) 函数的,咱们不关⼼,咱们只要知道编译器做了这样⼀层代码解析转换即可。
《C++语言程序》测试题及答案
《c++程序设计》(本科)一、判断题(错误的在后面写“F”,正确的写“T”,每题1分)1. 程序是描述算法的编程工具。
T2. 将函数模板与某个具体数据类型连用,就产生了模板函数,称这个过程为函数模板实例化。
T3. C++语言中,用来为对象初始化的特殊成员函数称为构造函数;用于在对象撤销时执行一些清理任务的特殊成员函数称为析构函数。
T4. 逐条翻译并执行的翻译程序称为编译程序。
F5. 把所有类组织在一个树形结构中,这时所有类,不管它们之间的差别有多大,都有一个共同的相关类,这种结构被称为类树。
类群是由一些彼此密切相关的类和类族组成的。
F 6. 如果在定义一个类时,该类继承了多个基类的特征,那么这个继承关系称为多重继承。
T7. 不同对象可以调用相同名称的函数,并可导致完全相同的行为的现象称为多态性。
F8.形式参数表是用括号分隔的变量说明列表,变量称为函数的形式参数,有时也简称为形参。
F9..在C++语言中,只要在声明函数原型时形式参数的个数或者对应的类型不同,两个或更多的函数就可以共用同一个名字。
这种在同一作用域中允许多个函数使用同一函数名的措施被称为重载。
T8.C++的作用域分辨:可以迫使编译器“看到”当前作用域的外层部分,存取那些被隐藏的名字。
这是由作用域分辨操作符实现的,这一过程叫做作用域分辨。
T11.说明函数原型时不需要指明每个函数参数的名字,只需要说明每个参数的类型和返回值类型就可以了。
T12.所有的表达式都有值。
F13.程序的编译是以文件为单位的,因此将程序分到多个文件中可以减少每次对程序修改所带来的编译工作量。
T14.类的静态数据成员需要在定义每个类的对象时进行初始化。
F15.基类中被说明为protected和private的成员只能被其派生类的成员函数访问,不能被其它的函数访问。
F16.当将一个类S定义为另一个类A的友元类时,类S的所有成员函数都可以直接访问类A的所有成员。
T17.当函数的返回值是数组类型的,传递的是数组第一个元素的地址。
C++常见笔试题
C++方面:1、C++中内存分部可以几个区,各个分区的基本情况;在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。
里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)2、C++(有子类继承父类的情况下)构造函数、析构函数的执行顺序先执行父类的构造函数,接着执行子类的构造函数,然后执行子类的析构函数,最后执行父类的构造函数。
3、介绍一下虚函数,虚函数的作用,怎么调用;只有虚函数的类叫什么,为什么?虚函数主要作用是现象多态性。
可以通过基类指针指向即可。
只有虚函数的类为抽象类。
因为只有虚函数的类不能实例化。
4、进程与线程的区别进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。
它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。
通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。
在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。
答:线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
C++常见面试题30道
C++常见⾯试题30道1.new、delete、malloc、free关系delete会调⽤对象的析构函数,和new对应free只会释放内存,new调⽤构造函数。
malloc与free是C++/C语⾔的标准库函数,new/delete是C++的运算符。
它们都可⽤于申请动态内存和释放内存。
对于⾮内部数据类型的对象⽽⾔,光⽤maloc/free⽆法满⾜动态对象的要求。
对象在创建的同时要⾃动执⾏构造函数,对象在消亡之前要⾃动执⾏析构函数。
由于malloc/free是库函数⽽不是运算符,不在编译器控制权限之内,不能够把执⾏构造函数和析构函数的任务强加于malloc/free。
因此C++语⾔需要⼀个能完成动态内存分配和初始化⼯作的运算符new,以及⼀个能完成清理与释放内存⼯作的运算符delete。
注意new/delete不是库函数。
2.delete与 delete []区别delete只会调⽤⼀次析构函数,⽽delete[]会调⽤每⼀个成员的析构函数。
在More Effective C++中有更为详细的解释:“当delete操作符⽤于数组时,它为每个数组元素调⽤析构函数,然后调⽤operator delete来释放内存。
”delete与new配套,delete []与new []配套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-处报错。
这就说明:对于内建简单数据类型,delete和delete[]功能是相同的。
对于⾃定义的复杂数据类型,delete和delete[]不能互⽤。
delete[]删除⼀个数组,delete删除⼀个指针。
C++考试精彩试题重点
一、概念题1.类和对象有什么区别和联系?类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的操作封装在一起的集合体。
类是对某一类对象的抽象,而对象是某一种类的实例。
2.什么是类的实现?将类所有未编写函数体的成员函数在类体外全部编写出来。
3.this指针的概念是什么?类中所有的成员函数(静态成员函数除外)都隐含了第一个参数,这个隐含的第一个参数就是this指针,在成员函数的实现代码中,所有涉及对类的数据成员的操作都隐含为对this 指针所指对象的操作。
4.为什么要引入构造函数和析构函数?构造函数的作用是为类对象的数据成员赋初值,构造函数在定义类对象时由系统自动调用;在一个对象死亡或者说退出生存期时,系统会自动调用析构函数,因此可以在析构函数定义中,设置语句释放该对象所占用的一些资源。
5.什么时候需要自定义拷贝构造函数?若程序员没有定义拷贝构造函数,则编译器自动生成一个缺省的拷贝构造函数,它可能会产生什么问题?当有用一个已经存在对象创建一个同类型的新对象的需求时。
当对象含有指针数据成员,并用它初始化同类型的另一个对象时,默认的拷贝构造函数只能将该对象的数据成员复制给另一个对象,而不能将该对象中指针所指向的内存单元也复制过去。
这样,就可能出现同一内存单元释放两次,导致程序运行出错。
6.什么是堆对象?创建和回收堆对象的方法是什么?堆区用来存放在程序运行期间,根据需要随时建立的变量(对象),建立在堆区的对象称为堆对象,当堆对象不再使用时,应予以删除,回收所占用的动态内存。
创建和回收堆对象的方法是使用new和delete运算符。
7.为什么需要静态数据成员?静态数据成员的定义和初始化方法是什么?定义静态数据成员是为了同一个类的不同对象之间共享公共数据成员;用关键字static 可以把数据成员定义成静态数据成员;在定义的类被使用前,要对其中的静态数据成员进行初始化,初始化时不必添加关键字static。
调用析构函数
调用析构函数在C++编程中,析构函数是一种特殊的函数,它在对象被销毁时自动调用。
析构函数的作用是释放对象占用的资源,包括堆内存、文件句柄、网络连接等。
如果对象没有析构函数,那么这些资源将无法被释放,从而导致内存泄漏、文件锁定等问题。
因此,正确使用析构函数是C++编程中非常重要的一环。
本文将介绍析构函数的基本概念、调用时机、语法规则、常见错误等问题,并通过实例演示如何正确使用析构函数。
一、析构函数的基本概念1. 析构函数的定义析构函数是一种特殊的成员函数,它没有返回值,也不需要显式调用。
析构函数的名称与类名相同,前面加上“~”符号。
例如,类A的析构函数的名称为“~A”。
2. 析构函数的作用析构函数的作用是在对象被销毁时自动调用,释放对象占用的资源。
由于C++中没有垃圾回收机制,因此需要程序员自己手动释放对象占用的资源。
如果对象没有析构函数,那么这些资源将无法被释放,从而导致内存泄漏、文件锁定等问题。
3. 析构函数的调用时机析构函数的调用时机是在对象被销毁时自动调用。
对象被销毁的时机有以下几种情况:(1) 局部对象的作用域结束时,例如函数执行完毕时。
(2) 动态分配的对象使用delete操作符手动释放时。
(3) 静态对象在程序结束时被销毁。
(4) 成员对象在它所属的对象被销毁时被销毁。
二、析构函数的语法规则1. 析构函数的声明析构函数的声明与普通成员函数的声明相同,只是在函数名前面加上“~”符号。
例如:class A {public:A(); //构造函数~A(); //析构函数};2. 析构函数的定义析构函数的定义与普通成员函数的定义相同,只是在函数名前面加上“~”符号。
例如:A::~A() {//释放资源的代码}3. 析构函数的调用析构函数的调用不需要显式调用,它会在对象被销毁时自动调用。
例如:A* p = new A(); //动态分配一个对象delete p; //手动释放对象,调用析构函数{A a; //局部对象} //作用域结束,调用析构函数static A a; //静态对象int main() {return 0;} //程序结束,调用析构函数三、常见错误与解决方法1. 析构函数的访问权限析构函数的访问权限必须是public,否则无法被外部调用。
C中的析构函数和delete的关系
C中的析构函数和delete的关系析构函数1.构造函数是初始化对象的非static数据成员,在函数体中还可以另外做一些事情;析构函数则是释放对象使用的资源,并销毁对象的非static数据成员。
析构函数,没有返回值,也不接受参数(导致不能被重载),所以对于一个给定的类,只会有一个唯一的构造函数。
格式如下:~A();2.构造函数与析构函数的执行过程区别在构造函数中,先执行成员的初始化,且按照它们在类中出现的顺序进行初始化,然后执行函数体中的内容。
在析构函数中,首先执行的是函数体,然后销毁成员。
成员按初始化顺序的逆序进行销毁。
所以你要认识到,析构函数体自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。
在整个对象销毁过程中,析构函数体是作为成员销毁步骤之外的另一部分进行的。
在一个析构函数中,不存在类似构造函数中初始化列表的东西来控制成员如何销毁,也就是说,看不见析构的过程是如何进行的。
销毁类类型的成员需要执行成员自己的析构函数。
内置类型没有析构函数,因此,销毁内置类型成员什么也不需要做。
所以销毁一个内置指针类型的成员需要我们手动delete。
与普通指针不同,智能指针是类类型,所以具有析构函数,因此智能指针成员在析构阶段会自动销毁。
3.析构函数在什么情况下会被调用总的原则就是:当一个对象被销毁时,就会自动调用其析构函数。
具体情况如下变量在离开其作用域时被销毁。
当一个对象被销毁时,其成员被销毁。
容器(包括标准库容器和数组)被销毁时,其元素被销毁。
动态分配的对象,当对指向它的指针应用delete运算符时被销毁。
对于临时对象,当创建它的完整表达式结束时被销毁。
delete干了什么delete之后,下次再重新申请的时候可以申请这块内存地址,也就是将这块地址放到了空闲链表上。
如果你没有将p赋为NULL,那么p指针还是指向这块内存空间。
只不过这个位置的内存数据已经被毁尸灭迹,此时的这个指针指向的内存就是一个垃圾内存。
C++程序设计19秋在线作业2 假定指针变量p定义 int p new int 100 要释放p所指向的动态内存 应使用语句
C++程序设计19秋在线作业21 单选题1 假定指针变量p定义“int *p=new int(100);”,要释放p所指向的动态内存,应使用语句()。
CA delete *p;B delete &p;C delete p;D delete []p;2 下面关于运算符重载的描述错误的是()。
CA 重载不能改变操作数的个数、运算符的优先级、运算符的结合性和运算符的语法结构B 不是所有的运算符都可以进行重载C 运算符函数的调用必须使用关键字operatorD 在C++语言中不可通过运算符重载创造出新的运算符3 类中定义的成员默认为()访问属性。
BA publicB privateC protectedD friend4 下列选项中,()是istream类的对象。
AA cinB coutC cerrD clog5 析构函数是一种特殊的成员函数,显式定义时其访问属性应被定义为()。
AA publicB privateC protectedD static6 关于函数模板,描述错误的是()。
AA 函数模板必须由程序员实例化B 函数模板的实例化由编译器实现C 一个类定义中,只要有一个函数模板,则这个类是类模板D 若类模板的成员函数是函数模板,则类模板实例化后,成员函数也随之实例化7 下列关于运算符重载的描述中,正确的是()。
DA 可以改变运算符的目数B 可以改变运算符的优先级C 可以改变运算符的结合性D 可以改变运算符的功能8 面向对象程序设计将数据与()放在一起,作为一个相互依存、不可分割的整体来处理。
AA 对数据的操作B 信息C 数据隐藏D 数据抽象9 在C++中,编写一个内联函数Fun,使用int类型的参数,求其平方并返回,返回值也为int类型,下列定义正确的是()。
BA int Fun(int x){return x*x;}B inline int Fun(int x){return x*x;}C int inline Fun(int x){return x*x;}D int Fun(int x){inline return x*x;}10 定义类模板时要使用关键字()。
C++测试题
C++测试题C++测试题一、填空题(30空* 1分)1.在C++中,函数的参数有两种传递方式,它们是值传递和________。
2.当一个成员函数被调用时,该成员函数的__this对象指针_____指向调用它的对象。
3.在基类和派生类中,派生类可以定义其基类中不具备的数据和操作。
对两个有相同名字的数据成员进行访问时,如果没有____________,对此数据成员的访问将出现歧义。
4.拷贝构造函数使用___引用_____作为参数初始化创建中的对象。
5.在公有继承的情况下,基类数据成员在派生类中的访问权限_不变_________。
6. 建立一个有成员对象的多态派生类对象时,各构造函数体的执行顺序为_先基类按继承顺序,再成员对象按声明顺序,最后派生类本身_________________7.用new申请某一个类的动态对象数组时,在该类中必须能够匹配到_____默认___________构造函数,否则应用程序会产生一个编译错误。
8.静态数据成员在类外进行初始化,且静态数据成员被类的所有对象__共享______。
9.为了避免可能出现的歧义,C++对if…else语句配对规则规定为:else总是___与之前最近的if_____________配对。
10.设"int a=3,b=4,c=5;",表达式"(a+b)>c&&b==c"的值是_0___。
11.面向对象的程序设计有四大特征,它们是抽象、封装、_继承_____ 、_多态_______。
12.定义重载函数时,应至少使重载函数的参数个数或参数类型__不同_____;在基类和派生类中,成员函数的覆盖是指__________________________________________________。
13.构造函数与析构函数除功能不同外,在定义形式上,它们的区别还包括构造函数名与类名相同,而析构函数名是在类名前加一个~、但析构函数没有__重载___________, 但可以定义为_____虚函数____________14.动态联编要满足两个条件,它们是____多态_________________,____赋值兼容原则______________ 。
C++ 自考填空题试题库
21.在C++语言的面向对象设计框架中,_______是程序的基本组成单元。
22.执行代码double pi=3.1415192; cout < < setprecision (3) < < pi;程序的输出结果是_______。
23.C++语言提供的的基本控制结构可以分为3种类型:顺序结构、_______和循环结构。
24.要使用STL库提供的对数组进行降幂排序算法,在源程序中需要包含的头文件是______。
25.在C++标准库中,用_______类来表示复数。
26.将对象作为函数参数,是将实参对象的_______传递给形参对象,这种传递是单向的。
27.C++函数的返回类型可以是除数组与_______以外的任何类型。
28.能提供封装的C++关键字是_______。
29.在C++的类声明中,用public关键字声明的类成员的访问权限是_______。
30.开发一个C++语言程序的步骤通常包括编辑、_______、连接、运行和调试。
31.C++类中的_______函数在对象的生存期结束时被自动调用。
32.友元函数可以存取类的_______、公有成员和保护成员。
33.若类的成员函数用关键字static进行修饰,这样的成员函数称为_______。
34.在C++中,创建派生类对象时,总是先从_______的初始化开始的。
35.类的继承是指派生类继承基类的数据成员和_______。
36.在C++中,利用向量类模板定义一个具有20个double的向量,其元素均被置为0.5,实现此操作的语句是_______。
37.vector类中用于返回向量中的最后一个对象的方法是_________。
38.虚函数类似于重载函数,但与重载函数的实现策略不同,对虚函数声明时应使用_______关键字。
39.在C++中,虽然友元提供了类之间数据进行访问的一种方式,但它破坏了面向对象程序设计的_______特性。