C++拷贝构造函数
计算机二级C++考试备考练习题及答案
计算机二级C++考试备考练习题及答案选择题1、下列叙述中错误的是( )。
A.gets函数用于从终端读入字符串B.getchar函数用于从磁盘文件读入字符C.fputs函数用于把字符串输出到文件D.fwrite函数用于以二进制形式输出数据到文件正确答案:B答案解析:本题考查的是C语言中输入、输出函数的使用,gets和getchar 函数用于从标准输入设备键盘读入字符串和字符;fputs用于把字符串输出到文件;fwrite用于以二进制形式输出数据到文件。
2、拷贝构造函数的参数一般是( )A.某对象名B.某对象成员名C.某对象的引用名D.指向对象的指针名正确答案:C3、C++语言是以哪种语言为基础逐渐发展演变而成的一种程序设计语言( )A.ASPB.CC.VBD.Java正确答案:B4、软件设计中划分模块的一个准则是( ).A.低内聚低耦合B.高内聚低耦合C.低内聚高耦合D.高内聚高耦合正确答案:B答案解析:一般较优秀的软件设计,应尽量做到高内聚,低耦合,即减弱模块之间的耦合性和提高模块内的内聚性,有利于提高模块的独立性。
5、下述关于数据库系统的叙述中,正确的是( )。
A.数据库系统减少了数据冗余B.数据库系统避免了一切冗余C.数据库系统中数据的一致性是指数据类型一致D.数据库系统比文件系统能管理更多的数据正确答案:A答案解析:数据库系统会减少数据冗余,但不可能避免一切冗余。
6、关于纯虚函数,下列表述中正确的是( )。
A.纯虚函数是没有给出实现版本(即无函数体定义)的虚函数B.纯虚函数的声明总是以″=0″结束C.派生类必须实现基类的纯虚函数D.含有纯虚函数的类不可能是派生类正确答案:B答案解析:纯虚函数是在声明虚函数时被″初始化″为O的虚函数。
纯虚函数没有函数体,纯虚函数的作用是在基类中为其派生类保留一个函数名称。
7、下列描述中错误的是( )A.派生类可以作为基类派生其他的子类B.派生类继承基类的所有数据成员C.派生类可以有多个基类D.派生类不能继承一些函数成员正确答案:B8、已知int m= 10;在下列定义引用的语句中,正确的是( )。
详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现
详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现C++中⼀般创建对象,拷贝或赋值的⽅式有构造函数,拷贝构造函数,赋值函数这三种⽅法。
下⾯就详细⽐较下三者之间的区别以及它们的具体实现1.构造函数构造函数是⼀种特殊的类成员函数,是当创建⼀个类的对象时,它被调⽤来对类的数据成员进⾏初始化和分配内存。
(构造函数的命名必须和类名完全相同)⾸先说⼀下⼀个C++的空类,编译器会加⼊哪些默认的成员函数默认构造函数和拷贝构造函数析构函数赋值函数(赋值运算符)取值函数**即使程序没定义任何成员,编译器也会插⼊以上的函数!注意:构造函数可以被重载,可以多个,可以带参数;析构函数只有⼀个,不能被重载,不带参数⽽默认构造函数没有参数,它什么也不做。
当没有重载⽆参构造函数时,A a就是通过默认构造函数来创建⼀个对象下⾯代码为构造函数重载的实现<span style="font-size:14px;">class A{int m_i;Public:A(){Cout<<”⽆参构造函数”<<endl;}A(int i):m_i(i) {} //初始化列表}</span>2.拷贝构造函数拷贝构造函数是C++独有的,它是⼀种特殊的构造函数,⽤基于同⼀类的⼀个对象构造和初始化另⼀个对象。
当没有重载拷贝构造函数时,通过默认拷贝构造函数来创建⼀个对象A a;A b(a);A b=a; 都是拷贝构造函数来创建对象b强调:这⾥b对象是不存在的,是⽤a 对象来构造和初始化b的!!先说下什么时候拷贝构造函数会被调⽤:在C++中,3种对象需要复制,此时拷贝构造函数会被调⽤1. 1)⼀个对象以值传递的⽅式传⼊函数体2. 2)⼀个对象以值传递的⽅式从函数返回3. 3)⼀个对象需要通过另⼀个对象进⾏初始化什么时候编译器会⽣成默认的拷贝构造函数:1. 1)如果⽤户没有⾃定义拷贝构造函数,并且在代码中使⽤到了拷贝构造函数,编译器就会⽣成默认的拷贝构造函数。
C++自测题之三
一选择题1、面向对象程序设计中的数据隐藏指的是( D )。
A. 输入数据必须输入口令B. 数据经过加密处理C. 对象部数据结构上建有防火墙D. 对象部数据结构的不可访问性2、以下关于类的访问权限的描述中,错误的选项是( D ).。
A. 说明为公有的成员可以被程序中的任何代码访问B. 说明为私有的成员只能被类的成员和说明为友元类的成员函数访问C.说明为保护的成员,除了能被本身的成员函数和说明为友元类的成员函数访问外,该类的派生类的成员也可以访问D. 类的所有成员都可以被程序中的任何代码访问3、 C 中对于类中定义的成员,其默认的访问权限为( C )。
A. PublicB. ProtectedC. PrivatD. Static4、C++ 对C语言作了很多改良,即从面向过程变成为面向对象的主要改良是( D )A. 增加了一些新的运算符B. 允许函数重载,并允许设置缺省参数C. 规定函数说明符必须用原型D. 引进了类和对象的概念5、类A中的一个成员函数的说明如下:void Set(A &a);那么该函数的参数“A &a〞的含义是( C )。
A. 指向A的指针为aB. 将变量a的地址赋给类AC. 类A对象引用a用作函数的形参D. 变量A与a按位与后作函数参数6、以下特性中,C与C++共有的是( D )。
A. 继承B. 封装C. 多态性D. 函数定义不能嵌套7、关于封装,以下说法中不正确的选项是〔 D 〕。
A. 通过封装,对象的全部属性和操作结合在一起,形成一个整体B. 通过封装,一个对象的实现细节被尽可能地隐藏起来〔不可见〕C. 通过封装,每个对象都成为相对独立的实体D. 通过封装,对象的属性都是不可见的8、在一个类的定义中,包含有〔 C 〕成员的定义。
A. 数据B. 函数C.数据和函数D. 数据或函数9、在类作用域中能够通过直接使用该类的〔 D 〕成员名进展访问。
A. 私有B. 公用C. 保护D. 任何10、在关键字public后面定义的成员为类的〔 B 〕成员。
聊城大学计算机学院面向对象的程序设计(c++)练习题(第三周)(构造函数和析构函数)
聊城大学计算机学院面向对象的程序设计第三次作业一、单选题(本大题共17小题,每题3分,共51分):1、在下列函数原型中,可以作为类AA构造函数的是()。
A void AA(int);B int AA( );C AA(int) const;D AA(int);2、下列选项中,哪一项功能是对对象进行初始化()。
A 析构函数B 数据成员C 构造函数D 静态成员函数3、假定A为类名,执行A x;语句时将自动调用该类的()。
A 有参构造函数B 无参构造函数C 拷贝构造函数D 赋值构造函数4、下列关于构造函数的说法,错误的是()。
A 系统可以提供默认的构造函数B 构造函数可以有参数,所以可以有返回值C 构造函数可以重载D 构造函数可以设置默认参数5、有如下类定义:class Point{int x, y;public:Point__________:x_(0), y_(0){}Point(int x, int y = 0):x_(x), y_(y){}};若执行语句:Point a(2), b[3], *c[4];则Point类的构造函数被调用的次数是()。
A 2次B 3次C 4次D 5次6、在下面的类定义中class sample{public:sample(int val); //①~sample( ); //②private:int a=2.5; //③public:sample( ); //④};其中错误的语句是()。
A ①B ②C ③D ④7、假定一个类的构造函数为A(int i = 4, int j = 0) { a = i; b = j;}则执行A x(1)语句后,x.a和x.b的值分别为()。
A 1和0B 1和4C 4和0D 4和18、下列关于构造函数的描述中,错误的是()。
A 构造函数可以设置默认参数B 构造函数在定义类对象时自动执行C 构造函数可以是内联函数D 构造函数不可重载9、下列选项中,哪一项不是构造函数的特征()。
C++拷贝(复制)构造函数详解
C++拷贝(复制)构造函数详解⼀. 什么是拷贝构造函数⾸先对于普通类型的对象来说,它们之间的复制是很简单的,例如:[c-sharp]1. int a = 100;2. int b = a;⽽类对象与普通对象不同,类对象内部结构⼀般较为复杂,存在各种成员变量。
下⾯看⼀个类对象拷贝的简单例⼦。
[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //⼀般函数13. void Show ()14. {15. cout<<a<<endl;16. }17. };18.19. int main()20. {21. CExample A(100);22. CExample B = A; //注意这⾥的对象初始化要调⽤拷贝构造函数,⽽⾮赋值23. B.Show ();24. return 0;25. }运⾏程序,屏幕输出100。
从以上代码的运⾏结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。
就类对象⽽⾔,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
下⾯举例说明拷贝构造函数的⼯作过程。
[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //拷贝构造函数13. CExample(const CExample& C)14. {15. a = C.a;16. }17.18. //⼀般函数19. void Show ()20. {21. cout<<a<<endl;22. }23. };24.25. int main()26. {27. CExample A(100);28. CExample B = A; // CExample B(A); 也是⼀样的29. B.Show ();30. return 0;31. }CExample(const CExample& C) 就是我们⾃定义的拷贝构造函数。
c++课后习题解答6-10
};
int S::IsMemberOf(int n)
{
for(int i=0;i<PC;i++)
if(elems[i]==n)
return 1;
return 0;
}
int S::Add(int n)
{
if(IsMemberOf(n))
return 1;
else if(PC==100)
√24.友元类中的所有成员函数都是友元函数。
√25.类型转换函数是一种特殊的成员函数,定义时不加类型说明,无函数参数。
√26.单参数的构造函数具有类型转换的作用。
6.2单选题
1.下列关于类的定义格式的描述中,错误的是(C)。
A.类中成员有3种访问权限
B.类的定义可分说明部分和实现部分
C.类中成员函数都是公有的,数据成员都是私有的
答:编程如下:
#include <iostream.h>
class ASMD
{
public:
ASMD(double a,double b)
{ x=a; y=b; }
void Addition()
{ cout<<x+y<<endl; }
void Subtration()
{ cout<<x-y<<endl; }
a.Print();
b.Print();
}
答:Default constructor called.
Constructor called.
a1=0,a2=0
a1=5,a2=8
Destructor called.
C++试题(一)附答案
C++试题(一)附答案一、单项选择题(共20题,每题1分,共20分)1、下列关于C++标识符的命名不合法的是A. PadB. name_1C. A#bcD. _a122、若有以下类型标识符定义:()int x=2; char w='a'; float y=23.45f; double z=45.6712;则表达式w*x+y-z的结果类型是A. floatB. charC. intD. double3、若有int x=10,y=20,z=30; 则执行下面语句后,x的值是if(x>y)z=x;x=y;y=z;A. 10B. 20C. 30D. 04、循环语句whlie(int i=0 )i--;的循环次数是A. 0B. 1C. 5D. 无限5、一个函数无返回值时,应选择的说明符是A. staticB. externC. voidD. 无说明符6、对重载函数形参的描述中,错误的是A. 参数的个数可能不同B. 参数的类型可能不同C. 参数的顺序可能不同D. 参数的个数、类型、顺序都相同,只是函数的返回值类型不同7、以下能正确定义数组并正确赋初值的语句是A. 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、下列给字符数组进行的初始化中,不正确的是A. char s1[]="abcd";B. char s2[3]={'x','y','\0'};C. char s3[]={'a','x','y','\0'};D. char s4[6]={"xyz","mnp"};9、通常的拷贝构造函数的参数是A.某个对象名 B.某个对象成员名C.某个对象的引用 D.某个对象的指针名10、关于构造函数特点的描述中,错误的是A. 定义构造函数必须指出类型B. 构造函数的名字与该类的类名相同C. 一个类中可定义0至多个构造函数D. 构造函数是一种成员函数11、下面程序的运行结果为#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、关于常成员的描述中,错误的是A. 常成员包含常数据成员和常成员函数两种B. 常数据成员必须是公有的C. 常数据成员要使用构造函数成员初始化列表进行初始化D. 常对象只能调用它的常成员函数,不能调用其它的成员函数13、关于友元函数的描述中,错误的是A. 友元函数不是成员函数B. 友元函数只能访问类中私有成员C. 友元函数破坏隐藏性,尽量少用D. 友元函数说明在类体内,使用关键字friend14、如果有int x,*p; float y,*q;则下面操作正确的是A.p=x B.p=qC.p=&x D.p=&y15、若有函数说明void fA(int m, int n); 和指针变量的定义 void (*p)(int,int);并且有p= fA 则下列操作不正确的是A.(*p)(3,4); B.p(3,4);C.fA(3,4); D.*p++;16、若数组名作实参而指针变量作形参,函数调用时实参传给形A. 数组的长度B. 数组第一个元素的值C. 数组所有元素的值D. 数组第一个元素的地址17、对于动态分配内存空间描述正确的是A.使用new运算符分配的内存空间的长度必需是常量B.delete运算符可以释放动态的存储空间和静态的存储空间C.由new分配的内存空间是不连续的D.delete运算符只能释放由new分配的动态存储空间18、能够释放对象所占资源的是()A.析构函数 B.数据成员C.构造函数 D.静态成员函数19、虚函数的定义是在基类中进行的,定义时需要冠以关键字A.static B.frendC.virtual D.public20、在C++中串流类是在头文件strstrea.h中定义的,下列不属于串流类的是)A.strstream B.ostrstreamC.ofstream D.istrstream二、填空题(共9题16空,每空1分,共16分)1、函数重载时,编译系统会根据____ 或____ 来区分。
C选择题填空题
C选择题填空题一、填空题1、在类中必须声明成员函数的( ),成员函数的( )部分可以写在类外。
[答案]原型实现2、如果需要在被调函数运行期间,改变主调函数中实参变量的值,则函数的形参应该是( )类型或()类型。
[答案]引用指针3、()类只能作为基类使用,而不能声明它的对象。
[答案]抽象4、拷贝构造函数的形参必须是()[答案]本类对象的引用5、进行函数重载时,被重载的同名函数如果都没有用const修饰,则它们的形参()或()必须不同。
[答案]个数类型6、通过一个()对象只能调用它的常成员函数,不能调用其他成员函数。
[答案]常二、选择题1、编译时多态性使用什么获得?(A)A. 重载函数B. 继承C. 虚函数D. B和C2、假定MyClass为一个类,则该类的拷贝构造函数的声明语句为(C)。
A.MyClass(MyClass x)B.MyClass&(MyClass x)C.MyClass(MyClass &x)D.MyClass(MyClass *x)3、列带缺省值参数的函数说明中,正确的说明是(C)1. A. int Fun(int x=1, int y, int z=3);B. int Fun(int x, int y=2, int z);C. int Fun(int x, int y, int z=3);D. int Fun(int x=1, int y, int z);4、下列有关函数重载的叙述中,错误的是(A)A.函数重载就是用相同的函数名定义多个函数B.重载函数的参数列表必须不同C.函数的返回值类型不能用于对重载函数的区分D.const关键字可以用于对重载函数的区分5、在一个函数中,要求通过函数来实现一种不太复杂的功能,并且要求加快执行速度,选用(A)。
A. 内联函数B. 重载函数C. 递归调用D. 嵌套调用6、下列有关C++类的说法中,不正确的是(C)。
A. 类是一种用户自定义的数据类型B. 只有类中的成员函数或类的友元函数才能存取类中的私有成员C. 在类中,如果不做特别说明,所有成员的访问权限均为私有的D. 在类中,如果不做特别说明,所有成员的访问权限均为公用的7、Sample是一个类,执行下面语句后,执行Sample类的构造函数的次数是(D) Sample a[3], *p=new Sample;A.1B.2C.3D.48、关于常数据成员的说法,不正确的是(D)。
结构体拷贝构造函数
结构体拷贝构造函数
结构体是C语言中一种很常用的数据类型,它可以将不同类型的数据组合在一起,为使用者提供了很多方便。
对于结构体,有时当我们想要复制一个结构体时,就需要用到结构体拷贝构造函数,它可以将一个已经存在的结构体拷贝到新结构体中。
原来的结构体在构造函数中传入,该构造函数实现的功能是使用原始结构体的信息来构造一个新的结构体。
构造函数一般有两种,一种是深拷贝(deep copy),其中,拷贝函数会完全复制原来结构体里面的每个成员;另一种是浅拷贝(shallow copy),只会复制原来结构体里面的指针类型成员,而不会拷贝里面的值,也就是说,新的结构体里的指针类型成员,都指向原来的结构体里的成员。
对于深拷贝而言,不仅会拷贝结构体本身里面的成员,还会拷贝指针类型的成员;而对于浅拷贝,只会拷贝原来结构体里面的指针类型成员,指向的内容还是原来的结构体里的内容,而不会再开辟新的内存空间。
总之,结构体拷贝构造函数可以将一个已有的结构体拷贝到一个新的结构体中,数据会以浅拷贝或者深拷贝的方式进行复制,让用户更方便地实现数据复制。
CC++笔试题目大全(含答案)
C/C++笔试题目大全链表反转单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。
比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。
最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。
源代码如下:1. struct linka {2. int data;3. linka* next;4. };5. void reverse(linka*& head) {6. if(head ==NULL)7. return;8. linka *pre, *cur, *ne;9. pre=head;10. cur=head->next;11. while(cur)12. {13. ne = cur->next;14. cur->next = pre;15. pre = cur;16. cur = ne;17. }18. head->next = NULL;19. head = pre;20. }还有一种利用递归的方法。
这种方法的基本思想是在反转当前节点之前先调用递归函数反转后续节点。
源代码如下。
不过这个方法有一个缺点,就是在反转后的最后一个结点会形成一个环,所以必须将函数的返回的节点的next域置为NULL。
因为要改变head指针,所以我用了引用。
算法的源代码如下:1. linka* reverse(linka* p,linka*& head)2. {3. if(p == NULL || p->next == NULL)4. {5. head=p;6. return p;7. }8. else9. {10. linka* tmp = reverse(p->next,head);11. tmp->next = p;12. return p;13. }14. }②已知String类定义如下:class String{public:String(const char *str = NULL); // 通用构造函数String(const String &another); // 拷贝构造函数~ String(); // 析构函数String & operater =(const String &rhs); // 赋值函数private:char *m_data; // 用于保存字符串};尝试写出类的成员函数实现。
常用的16个cc++面试题
常⽤的16个cc++⾯试题1. C中static有什么作⽤ (1)隐藏。
当我们同时编译多个⽂件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使⽤static在不同的⽂件中定义同名函数和同名变量,⽽不必担⼼命名冲突。
(2)static的第⼆个作⽤是保持变量内容的持久。
存储在静态数据区的变量会在程序刚开始运⾏时就完成初始化,也是唯⼀的⼀次初始化。
共有两种变量存储在静态存储区:全局变量和static变量。
(3)static的第三个作⽤是默认初始化为0.其实全局变量也具备这⼀属性,因为全局变量也存储在静态数据区。
在静态数据区,内存中所有的字节默认值都是0×00,某些时候这⼀特点可以减少程序员的⼯作量。
2.C++中const有什么⽤? 不要⼀听到const就说是常量,这样给考官⼀种在和⼀个外⾏交谈的感觉。
应该说const修饰的内容不可改变就⾏了,定义常量只是⼀种使⽤⽅式⽽已,还有const数据成员,const参数, const返回值, const成员函数等,被const修饰的东西都受到强制保护,可以预防意外的变动,能提⾼程序的健壮性。
3. C与C++各⾃是如何定义常量的?有什么不同? C中是使⽤宏#define定义, C++使⽤更好的const来定义。
区别: 1)const是有数据类型的常量,⽽宏常量没有,编译器可以对前者进⾏静态类型安全检查,对后者仅是字符替换,没有类型安全检查,⽽且在字符替换时可能会产⽣意料不到的错误(边际效应)。
2)有些编译器可以对const常量进⾏调试,不能对宏调试。
4. 既然C++中有更好的const为什么还要使⽤宏? const⽆法代替宏作为卫哨来防⽌⽂件的重复包含。
5. C++中引⽤和指针的区别? 引⽤是对象的别名,操作引⽤就是操作这个对象,必须在创建的同时有效得初始化(引⽤⼀个有效的对象,不可为NULL),初始化完毕就再也不可改变,引⽤具有指针的效率,⼜具有变量使⽤的⽅便性和直观性,在语⾔层⾯上引⽤和对象的⽤法⼀样,在⼆进制层⾯上引⽤⼀般都是通过指针来实现的,只是编译器帮我们完成了转换。
c++ 类的拷贝构造函数
c++类的拷贝构造函数C++中的类拷贝构造函数是一个非常重要的概念,它允许在创建一个对象时从另一个对象中创建一个完全相同的副本。
在这篇文章中,我们将深入探讨拷贝构造函数的定义、使用和实现。
首先,我们需要了解拷贝构造函数的定义。
拷贝构造函数是一个可以接受同类型对象作为参数的特殊函数。
它的主要作用是创建一个新对象并将其初始化为传递的对象的副本。
以下是一个简单的拷贝构造函数的定义:```c++class MyClass{public:MyClass(const MyClass&other){//Copy constructor code here}};```在这个例子中,我们定义了一个名为MyClass的类,它有一个拷贝构造函数,该函数的参数是一个同类型对象的引用。
在函数体中,我们可以编写适当的代码来初始化新对象并从传递的对象中复制其状态。
接下来,让我们看看拷贝构造函数的实际用途。
假设我们有一个名为myObj的MyClass对象,并且我们想要从它创建一个完全相同的副本。
我们可以使用拷贝构造函数来实现这一点,如下所示:```c++MyClass myCopy(myObj);```在这里,我们声明了一个名为myCopy的新对象,并将myObj作为参数传递给拷贝构造函数。
当我们运行这个代码时,拷贝构造函数将会创建一个新的对象myCopy,并将myObj的状态复制到它里面。
另一个常见的用例是在函数参数中传递对象的副本。
我们可以使用拷贝构造函数来创建这个副本,并确保它是在函数操作之前完全独立的。
例如,如果我们有一个函数:```c++void doSomething(MyClass obj){//Function code here}```在这个函数中,我们将MyClass对象作为参数传递,并在其中执行某些操作。
通过使用拷贝构造函数创建一个对象副本,我们可以确保obj对象是独立于原始对象的,并且在函数操作期间不会与其他程序状态产生冲突。
c++期末复习题
一、填空题(每空1分,共15分,将正确答案写在()中)1.C++中有两种数据类型:( 整型)和( 字符型)可以使用signed修饰符。
在C++中,用数组、指针、和( 引用)作为函数参数,能够将参数值带回。
2.为了降低函数调用的时间开销,建议将小的调用频繁的函数定义为(内联函数),方法是在函数类型前加上(inline)关键字。
3.面向对象的程序设计有四大特征,它们是抽象、封装、( 继承)、( 多态)。
4.拷贝构造函数是在用一个对象初始化另一个对象时被调用,系统缺省的拷贝构造函数的工作方法是( 拷贝每一个数据成员)。
或逐一拷贝5.用new申请某一个类的动态对象数组时,在该类中必须能够匹配到(默认)构造函数,否则应用程序会产生一个编译错误。
6.静态数据成员必须在类外进行初始化,且静态数据成员的一个拷贝被类的所有对象( 共享)。
7.在C++中,定义重载函数时,应至少使重载函数的参数个数或参数类型( 有一个不同)。
8.在C++中,虽然友元提供了类之间数据进行访问的一种方式,但它破坏了面向对象程序设计的( 封装)特性。
9.预编译指令由三种,它们是:文件包含、( 宏定义)(条件编译)10.静态的成员函数没有隐含的( this指针),所以,它们只能直接访问类的静态的数据成员。
11.在C++中,函数的参数有两种传递方式,它们是值传递和( 引用传递)。
12.当非静态成员函数被调用时,该成员函数的( this指针)指向调用它的对象。
13.拷贝构造函数使用( 一个已经存在的对象)作为参数初始化创建中的对象。
14.在公有继承的情况下,基类数据成员在派生类中的访问权限( 保持不变)。
15.在C++中,构造派生类对象时,总是先从(基类)的初始化开始的。
16.当需要统计程序中某个类创建对象的个数时,需要给该类定义(静态数据)成员。
17.在多个类之间有重复继承时,为避免被重复继承的基类数据成员在内存中有多个拷贝,应将该基类定义为(虚基类)。
C++习题三
• 错误(1):printStu()和setSno()两个成员函 数没有用public定义,不允许在类外进行访 问。 • 错误(2):成员函数在类外定义,应加上 类名”Student::”。 • 错误(3) steAge()应该在类中说明为public 属性,并在类外定义时加上”Student::” • 错误(4)在主函数中加上”return 0”。
• int main() • { • return 0;}
• • 程序中在主函数外定义了类和对象,主函 数中只有一句return 0;为什么程序还会运行 类中定义的函数呢? • 如果是全局对象,可以调用构造函数和析 构函数
构造函数和析构函数
3.20 指出下列程序中的错误,并说明原因。 #include<iostream> • using namespace std; • class Student • { public: • void printStu(); • private: • char name[10]; • int age; • float aver; • }; • int main() • {Student p1,p2,p3; • p1.age=30; ……. return 0; }
3.17 假设在程序中已经声明了类point,并建立了其 对象p1和p4。请回答以下几个语句有什么区别? (1) point p2,p3; (2) point p2=p1; “赋值法” (3) point p2(p1); “代入法” (4) p4=p1; 通过默认赋值运算符函数实现将对象p1数 据成员的值拷贝到对象p4中。 答(1):使用带默认参数的构造函数或不带参数的构造 函数,定义了两个对象。 (2): 在建立新对象p2时,用已经存在的对象p1初始 化新对象p2,在这个过程中用“赋值法”调用了 拷贝构造函数。
C++复习试题(2010-1012)
2、简述静态多态性和动态多态性的不同。 在程序编译时系统就能决定调用哪个函数,称为静态多态性货 编译时的多态性。静态多态性是通过函数的重载实现的。 动态多态性是在程序运行过程中才动态地确定操作所针对的对 象。它又称运行时的多态性。动态多态性是通过虚函数来实现的。
3.运算符重载需要遵循哪些原则?
运算符重载不能改变运算符原有的含义;不能改变运算 符原有的优先级别和结合性;也不能改变运算符运算对象 (即操作数)的个数;不能创建新的运算符,只能重载C++已 有的运算符。不能重载的运算符有:.、.*、::、sizeof、?:。
11.C++中的模板包括( ) A)对象模板和函数模板 C)函数模板和类模板
B)对象模板和类模板 D)变量模板和对象模板
12.下列关于this指针的叙述中,正确的是( )
A)任何与类相关的函数都有this指针 B)类的成员函数都有this指针 C)类的友元函数都有this指针 D)类的非静态成员函数都有this指针
4.简述变量的引用与指针有什么区别? 变量的引用就是变量的别名,引用又称为别名。建立引用的 作用是为一个变量起另一个名字,对变量声明一个引用,并不另 开辟内存单元,特别地,在声明一个引用时,必须同时使之初始 化,即声明它代表哪一个变量。 变量的指针就是变量的地址,存放变量地址的变量是指针变 量,用来指向另一个变量。指针变量不同于整型变量和其他类型 的变量,它是用来专门存放地址的。 指针变量是独立的变量,编译系统给它单独分配存储单元, 而引用不是独立的变量,编译系统不给它单独分配存储单元。
9.在C++类中,有一种不能定义对象的类,这样的类只能被继承,称 之为 ,定义该类至少具有一个 。 10.在C++类中,const关键字可以修饰对象和成员函数,const对象不 能 ,const成员函数不能 。 11.在用class定义一个类时,数据成员和成员函数的默认访问权限 是 ;在用struct声明一个类时,数据成员和成员函数的默 认访问权限是 。。 12.定义模板的关键字是 ,内联函数的关键字是 。。
C、C++数据结构机试题
一:已知类String的原型为:classString{public:String(constchar*str=NULL);//普通构造函数String(constString);//拷贝构造函数~String(void);//析构函数String&operator=(constString);//赋值构造函数private:char*m_data;//用于保存字符串};请编写String的上述4个函数。
答案:版本1//String的析构函数String::~String(void)//3分{delete[]m_data;//由于m_data是内部数据类型,也可以写成deletem_data; }String::String(constchar*str){if(str==NULL){m_data=newchar[1];//若能加NULL判断则更好*m_data=‘{post.content}’;}else{intlength=strlen(str);m_data=newchar[length+1];//若能加NULL判断则更好strcpy(m_data,str);}}//拷贝构造函数String::String(constString&other){intlength=strlen(other.m_data);m_data=newchar[length+1];//若能加NULL判断则更好strcpy(m_data,other.m_data);}//赋值函数String&String:operate=(constString&other){//(1)检查自赋值if(this==&other)return*this;//(2)释放原有的内存资源delete[]m_data;//(3)分配新的内存资源,并复制内容intlength=strlen(other.m_data);m_data=newchar[length+1];//若能加NULL判断则更好strcpy(m_data,other.m_data);//(4)返回本对象的引用return*this;}版本2String::String(constchar*str){if(str){memset(m_data,0,strlen(m_data));strcpy(m_data,str);}else*m_data=0;}String::String(constString){strcpy(m_data,copy.m_data);}String&String:operator=(constString){if(this==)retrun*this;strcpy(m_data,copy.m_data);return*this;}版本3String::String(constchar*str){if(m_data)delete[]m_data;if(str){m_data=newchar[strlen(str)];memset(m_data,0,strlen(m_data));strcpy(m_data,str);}else*m_data=0;}String::String(constString){if(m_data)delete[]m_data;m_data=newchar[strlen(copy.m_data+1)]strcpy(m_data,copy.m_data);}String&String:operator=(constString){if(this==)retrun*this;if(m_data)delete[]m_data;m_data=newchar[strlen(copy.m_data+1)]strcpy(m_data,copy.m_data);return*this;}~String::String(void){if(m_data)delete[]m_data;}二:改错题,只能在原来的基础上增加代码,不能删除代码#include#includevoidfoo(intage,char*b){b=(char*)malloc(64);sprintf(b,"YourAgeis%d",age);}intmain(){char*f;foo(23,f);printf("%s\n",f);}答案版本1#include#includevoidfoo(intage,char**b){*b=(char*)malloc(64);sprintf(*b,"YourAgeis%d",age);}intmain(){char**f;foo(23,f);printf("%s\n",**f);return0;}版本2#include#includevoidfoo(intage,char*&b) {b=(char*)malloc(64);sprintf(b,"YourAgeis%d",age); }intmain(){char*f;foo(23,f);printf("%s\n",f);free(f);//不要忘了free;}三:有程序片断如下intmain(){intI=20;pid_tpid=5;if((pid=fork())>0){I=50;printf("%d\n",I);(1)}elseif(pid==0){printf("%d\n",I);(2)}}请问该程序用的是进程方式还是线程方式,并说明进程与线程的区别:请问该程序输出什么结果?无参考答案L四、constantpointerpointsforStringpointerpointsforconstantstring五、下面等价的是:Ainti=0if(i){printf("hello,world");}Binti=1;intj=2;if(i==1||j==2){printf("hello,world");}CBooleanb1=true;Booleanb2=true;if(b1==b2){printf("hello,world");}Dinti=1;intj=2;if(i==1&|j==2){printf("hello,world");}六、排序二叉树插入一个节点或双向链表的实现四~六为IBM面试题。
C程序设计题库及答案(精简)
【章节】第1章 C++基础知识【知识点】1、 C++程序的构成与书写形式;2、基本数据类型,常量、变量和表达式3、 C++的标准输入输出【单选题】1、在C++中,源程序变为可执行程序的正确顺序应该是( ) 。
A. 编辑、链接、编译、执行B. 编辑、编译、链接、执行C. 编译、编辑、链接、执行D. 编译、链接、编辑、执行答案:B2、要把高级语言编写的源程序转换为目标程序,需要使用( ) 。
A. 编辑程序B. 驱动程序C. 调试程序D. 编译程序答案:D3、下列关于C++与C语言的关系描述中,错误的是( ) 。
A. C语言是C++语言的一个子集B. C++与C语言是兼容的C. C++对C语言进行了一些改进D. C++和C语言都是面向对象的答案:D4、下面为使用面向对象语言的正确理由是( ) 。
A. 面向对象程序由三种基本结构组成,分别是顺序结构、选择结构和循环结构B. 程序语句比面向过程语言简单C. 面向对象程序设计可以设计为自行修改错误D. 面向对象程序很容易概念化答案:D5、以下选项中,合法的用户标识符是( ) 。
A. longB. _2TestC. 3DmaxD. A.dat答案:B6、下列描述中正确的是( ) 。
A. 不是每个C++程序都必须包含预处理命令#includeB. C++程序必须有return 语句C. C++程序中的变量必须定义在主程序内部D. C++程序中所使用的符号常量可以不进行定义答案:A7、C++源程序文件的扩展名为( ) 。
B. .CC. .DLLD. .EXE答案:A8、cout是I0流库预定义的( ) 。
A. 类B. 对象C. 包含文件D. 常量答案:B9、 C++对C语言作了很多改进,即从面向过程变成为面向对象的主要原因是( ) 。
A. 增加了一些新的运算符B. 允许函数重载,并允许设置缺省参数C. 规定函数说明符必须用原型D. 引进了类和对象的概念答案:D10、下列选项中,( ) 是不合法的标识符.A. ProgramB. Obj23C. doubleD. B_C_D答案:C11、下列标识符中,不合法的用户标识符为( ) 。
C++面试必考问题(类)C++中class和struct 的区别,构造,析构,拷贝构造,空类,重载
8.4构造函数和析构函数
面试例题11:静态成员的使用
#include<iostream> using namespace std; class Test { public: static int i; int j; // Test(int a):i(1),j(a){} Test(int a):j(a){} void func1(); static void func2();//静态成员函数
//结构体 spt.print();//成员函数print为public,可以调用 // spt.print1();//成员函数print1为private,不能被调用 cout<<spt.x<<" "<<spt.y<<endl;//合法 return 0; } //结论:C++中的struct包含构造函数和成员函数,其实它还拥有class的其他特性, 如继承、虚函数等。 //因此C++中的struct扩充了C的struct功能。
}; //**************************指定private继承 ****************// struct SDerived2:private CBase {
};
//*****************************主函数*********************************// int main(void) { //类class CDerived1 cd1;//先调用父类构造函数,再调用自己的构造函数 CDerived2 cd2;//先调用父类构造函数,再调用自己的构造函数 // cd1.print();//默认为private继承,所以成员函数print()不能被调用 cd2.print();//指定为public继承,所以成员函数print()能被调用,显示为 CBase:print()…
C面向对象程序设计重点复习
面向对象程序设计复习题一、单项选择题1.下面关于对象概念的描述中,_______是错误的;BA.对象代表着正在创建的系统中的一个实体B.对象就是C语言中的结构体变量C.对象是一个状态和操作或方法的封装体D.对象之间的信息传递是通过消息进行的2. 继承机制的作用是: CA.信息隐藏B.数据封装C.定义新类D.数据抽象3.有关析构函数的说法不正确的是_________DA.析构函数有且只有一个B.析构函数无任何函数类型C.析构函数没有形参D.析构函数不能是虚函数4.友元的作用之一是__________AA.提高程序的运行效率B.加强类的封装性C.实现数据的隐藏性D.增加成员函数的种类5.通常拷贝构造函数的参数是__________;CA.某个对象名B.某个对象的成员名C.某个对象的引用名D.某个对象的指针名6.如果在基类中将show声明为不带返回值的纯虚函数,正确的写法是________;Cshow=0; void show;void show=0; show=0 virtual;7.下面关于友元的描述中,错误的是_________;DA.友元函数可以访问该类的私有数据成员B.一个类的友元类中的成员函数都是这个类的友元函数C.友元可以提高程序的运行效率D.类与类之间的友元关系可以继承8.在C++中,_________运算符不能重载;BA. +B.: D.<=9.下列关于运算符重载的描述中,________是正确的;DA.运算符重载可以改变操作数的个数B.运算符重载可以改变优先级C.运算符重载可以改变结合性D.运算符重载不可以改变语法结构10. 在下列函数原型中,可以作为类AA构造函数的是_________DA.void AAint ; B.int AA ; C.AAintconst; D.AAint;11.在声明类时,下面的说法正确的是_________;CA.可以在类的声明中给数据成员赋初值B.数据成员的数据类型可以是register,public,protected可以按任意顺序出现D.没有用private,public,protected定义的数据成员是公有成员12.继承具有________,即当基类本身也是某一个类的派生类时,底层的派生类也会自动继承间接基类的成员;BA.规律性B.传递性C.重复性D.多样性13.在多重继承中,公有派生和私有派生对于基类成员在派生类中的可访问性与单继承的规则___________;AA.完全相同B.完全不同C.部分相同,部分不同D.以上都不对14.对虚函数的调用__________;DA.一定使用动态联编B.必须使用动态联编C.一定使用静态联编D.不一定使用动态联编15.关于成员函数特征的下述描述中,_______是错误的;AA.成员函数一定是内置函数B.成员函数可以重载C.成员函数可以设置参数的默认值D.成员函数可以是静态的16. 下面关于c++语言变量的叙述错误的是_______BA.在c++语言中变量分为auto,static,extern和register四种存储类型B.自动变量和外部变量的作用域为整个程序C.内部变量的作用域是定义它的函数D.外部静态变量的作用域是定义它的文件17.下列的各类函数中,_______不是类的成员函数;CA.构造函数B.析构函数C.友元函数D.拷贝构造函数18. 有如下类声明:class Foo {ing bar ;};则Foo类的成员bar是_________CA.公有数据成员B.公有成员函数C.私有数据成员D.私有成员函数19.下列表示引用的方法中,__________是正确的;已知:int m=10; DA. float &t=&m; &y=10; &z; D. int &x=m;20.设置虚基类的目的是________;BA.简化程序B.消除二义性C.提高运行效率D.减少目标代码21.对于类中定义的成员,其隐含访问权限为________B22.关于类和对象不正确的说法是________ BA.类是一种类型,它封装了数据和操作B.一个类的对象只有一个C.对象是类的实例D.一个对象必属于某个类23.声明一个类的对象时,系统自动调用一个函数___c___;撤消对象时,系统自动调用一个函数;该函数为___c___A.成员函数;构造函数B.复制构造函数;析构函数C.构造函数;析构函数D.析构函数;复制构造函数24.当一个派生类私有继承一个基类时,基类中的所有公有成员和保护成员成为派生类的__A______ 成员成员成员 D.友元25.在C++中,要实现动态联编,必须使用_____D___调用虚函数A.类名B.派生类指针C.对象名D.基类指针26.若一个类中含有纯虚函数,则该类称为____A____A. 抽象类B. 纯基类C.派生类D. 基类27.下列关于this指针的叙述中,正确的是___D_____A.任何与类相关的函数都有this指针B.类的成员函数都有this指针C.类的友元函数都有this指针D.类的非静态成员函数才有this指针28.有如下类声明:class Book {int num ;};则Book类的成员num是___D_____A.公有数据成员B.公有成员函数C.私有数据成员D.私有成员函数29.下面有关重载函数的说法中正确的是___C_____A.重载函数必须具有不同的返回值类型;B.重载函数形参个数必须不同;C重载函数必须有不同的形参列表; D.重载函数名可以不同;30.设置虚基类的目的是___A_____A.消除二义性B.简化代码C.提高运行效率D.减少目标代码31.在C++语言程序中,对象之间的相互通信通过___B_____A.继承实现B.调用成员函数实现C.封装实现D.函数重载实现32.下列运算符中,在C++语言中不能重载的是__C______A. B.>= C.:: D./33.下面对友元函数描述正确的是___C_____A.友元函数的实现必须在类的内部定义B.友元函数是类的成员函数C.友元函数破坏了类的封装性和隐藏性D.友元函数不能访问类的私有成员34.下面叙述不正确的是___A_____A.基类的保护成员在派生类中仍然是保护成员B.基类的保护成员在公有派生类中仍然是保护成员C.基类的保护成员在私有派生类中是私有成员D.对基类成员的访问必须是无二义性35.下面对静态数据成员的描述中,正确的是___D_____A.静态数据成员可以在类体内进行初始化B.静态数据成员不可以被类的对象调用C.静态数据成员不能受private控制符的作用D.静态数据成员可以直接用类名调用36.在C++类语言体系中,不能被派生类继承的有_______BA.转换函数B.构造函数C.虚函数D.静态成员函数37.在类的定义中,用于为对象分配内存空间,对类的数据成员进行初始化并执行其他内部管理操作的函数是____C____A.友元函数B.虚函数C.构造函数D.析构函数38.下列关于虚基类的描述中,错误的是_B_______A.设置虚基类的目的是为了消除二义性;B.虚基类的构造函数在非虚基类之后调用;C.若同一层包含多个虚基类,这些基类的构造函数按照它们的次序调用;D.若虚基类由非基类派生而来,则仍然先调用基类构造函数,再用派生类的构造函数;39.考虑函数原型voidtestinta,int b=7,char="",下面的函数调用中,属于不合法调用的是___C_____A. test5 5,8 6,"" 0,0."";40.下列关于构造函数的描述中,错误的是___D_____A.构造函数可以设置默认参数;B.构造函数在定义类对象时自动执行C.构造函数可以是内联函数;D.构造函数不可以重载41.在重载一个运算符时,如果其参数表中有一个参数,则说明该运算符是 ; DA.一元成员运算符 B.二元成员运算符 C.一元友元运算符 D.选项B和选项C都可能42.在公有派生情况下,有关派生类对象和基类对象的关系,下列叙述不正确的是 ; CA.派生类的对象可以赋给基类的对象 B.派生类的对象可以初始化基类的引用C.派生类的对象可以直接访问基类中的成员 D.派生类的对象的地址可以赋给指向基类的指针43.下面关于虚函数的描述,错误的是 ; BA.在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数B.基类中说明了虚函数后,派生类中对应的函数也必须说明为虚函数C.虚函数可以是另一个类的友元函数,但不能是静态成员函数D.基类中说明的纯虚函数在其任何派生类中都必须实现44.定义派生类时,若不使用关键字显示地规定采用何种继承方式,则默认方式为 ; AA.私有继承 B.非私有继承 C.保护继承 D.公有继承45.有如下程序:includeusing namespace std;class ONE{int c;public:ONE:c0{cout<<1;}ONEint n:cn{cout<<2;}};class TWO{ONE onel;ONE one2;public:TWOint m:one2m{cout<<3;}};int main{TWO t 4 ;return 0 ;}运行时的输出结果是 ; CA.3B.23C.123D.21346.关于静态数据成员的描述中正确的是DA类的静态数据成员不是类的所有对象共享的数据B类的静态数据成员不能被类的成员函数调用C类的静态数据成员不能被类的构造函数调用D类的静态数据成员必须进行初始化47下面正确的是,在父类中的访问属性访问修饰符在子类中的访问属性CApublic,private不能直接访问 Bprotect,public,publicCprivate,public不能直接访问 Dprotect,private,protect48类A是类B的友元,类B是类C的友元,则下列说法正确的是DA类B是类A的友元B类C是类A的友元C类A是类C的友元D以上都不对49下列关于构造函数说法不正确的是CA构造函数必须与类同名 B构造函数可以省略不写C构造函数必须有返回值 D在构造函数中可以对类中的成员进行初始化50.类的析构函数的作用是DA一般成员函数的初始化 B类的初始化C对象的初始化D删除类创建的对象51.下列说法正确的是BA内联函数在运行时是将该函数的目标代码插入每个调用该函数的地方B内联函数在编译时是将该函数的目标代码插入每个调用该函数的地方C类的内联函数必须在类体内定义D类的内联函数必须在类体外通过加关键字inline定义52.下面对静态数据成员的描述中,正确的是DA静态数据成员可以在类体内进行初始化B静态数据成员不可以被类的对象调用C静态数据成员不能受private控制符的作用D静态数据成员可以直接用类名调用二、知识点1.实现运行时的多态性要使用虚函数;2.如果一个类至少有一个纯虚函数,那么就称该类为抽象类;3. 运算符重载不能改变操作符的个数、运算符的优先级、运算符的结合性和运算符的语法结构;4. 构造函数是一种特殊的成员函数,它主要用来为对象分配内存空间,对类的数据成员进行初始化并执行对象的其他内部管理操作;5. 静态成员函数不能直接引用类中说明的非静态成员;6. 引用是给对象取一个别名,它引入了对象的同义词;7.设置友元函数的目的是为能够访问该类的私有成员;8.运算符重载仍然保持原来的优先级、结合性和语法结构;9.基类的私有成员不能被派生类的成员访问;10.静态联编支持的多态性称为编译时的多态性,也称静态多态性;11.任何类中允许有三种访问权限的数据,这三种访问权限分别是public、private、protected;12.为了满足运算符“+”的可交换性,必须将其重载为友元函数;13.对于含有对象成员的派生类,其构造函数的执行顺序为:先执行基类的构造函数、再执行对象成员的构造函数,后执行派生类的构造函数;14.利用成员函数对双目运算符重载,其左操作数为this指针指出的对象,右操作数为成员函数参数;++允许在相同的作用域内以相同的名字定义几个不同实现的函数,称这种同一个函数名多个含义的现象为函数重载;16.通过使用new和delete两个运算符进行的分配为动态存储分配;17.当类定义中有数据成员为指针时,解决浅拷贝出现的运行错误的方法是编写拷贝构造函数;18.如果使用protected继承基类,其公有成员就会变成派生类的保护成员,其保护成员就会变成派生类的保护成员,其私有成员不能继承19.一个函数功能不太复杂但要求被频繁调用,应定义为内联函数;20.抽象类只能作为基类使用,而不能声明它的对象;21.构造函数可以重载,析构函数不可以重载;22.静态成员函数没有this指针;23.类有两个特殊的成员函数构造函数和析构函数;24.在表达式x+yz中,+是作为成员函数重载的运算符,是作为非成员函数重载的运算符;其中operator+有一个参数,operator有两个参数;25.一个派生类只有一个基类的情况称为单继承,而有多个直接基类的情况称为多继承;26.调用析构函数的次序正好与调用构造函数的次序相反;27. 非成员函数应说明为类的友元函数才能访问这个类的private成员;28. 通过使用new和delete两个运算符进行的分配为动态存储分配;29.如果类B继承了类A,则称类A为类B的基类,类B称为类A的派生类30. 表达式operator+x,y还可以表示为x+y ;31 C++语言中的多态性分为编译时的多态性和运行时的多态性;32将x+yz中的"+"用成员函数重载,""用友元函数重载,应解释为x. operator+operatory,z33如果要把返回值为void的函数A声明为类B的友元函数,则应在类B的定义中加入的语句是friend void A ;34派生类的成员一般分为两部分,一部分是从基类继承的成员,另一部分是自己定义的新成员;35继承的方式有公有继承、私有继承和保护继承3种;。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
拷贝构造函数是C++最基础的概念之一,大家自认为对拷贝构造函数了解么?请大家先回答一下三个问题:1.以下函数哪个是拷贝构造函数,为什么?1.X::X(const X&);2.X::X(X);3.X::X(X&, int a=1);4.X::X(X&, int a=1, b=2);2.一个类中可以存在多于一个的拷贝构造函数吗?3.写出以下程序段的输出结果, 并说明为什么?如果你都能回答无误的话,那么你已经对拷贝构造函数有了相当的了解。
1.#include <iostream></iostream>2.#include <string></string>3.4.struct X {5. template<typename T>6. X( T& ) { std::cout << "This is ctor." << std::endl; }7.8. template<typename T>9. X& operator=( T& ) { std::cout << "This is ctor." << std::endl; }10.};11.12.void main() {13. X a(5);14. X b(10.5);15. X c = a;16. c = b;17.}解答如下:1. 对于一个类X,如果一个构造函数的第一个参数是下列之一:a) X&b) const X&c) volatile X&d) const volatile X&且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.1.X::X(const X&); //是拷贝构造函数2.X::X(X&, int=1); //是拷贝构造函数2.类中可以存在超过一个拷贝构造函数,1.class X {2.public:3. X(const X&);4. X(X&); // OK5.};注意,如果一个类中只存在一个参数为X&的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化.1.class X {2.public:3. X();4. X(X&);5.};6.7.const X cx;8.X x = cx; // error如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数.这个默认的参数可能为X::X(const X&)或X::X(X&),由编译器根据上下文决定选择哪一个.默认拷贝构造函数的行为如下:默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.b)如果数据成员是一个数组,对数组的每一个执行按位拷贝.c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.3. 拷贝构造函数不能由成员函数模版生成.1.struct X {2. template<typename T>3. X( const T& ); // NOT copy ctor, T can't be X4.5. template<typename T>6. operator=( const T& ); // NOT copy ass't, T can't be X7.};8.原因很简单, 成员函数模版并不改变语言的规则,而语言的规则说,如果程序需要一个拷贝构造函数而你没有声明它,那么编译器会为你自动生成一个. 所以成员函数模版并不会阻止编译器生成拷贝构造函数, 赋值运算符重载也遵循同样的规则.(参见Effective C++ 3edition, Item45)默认拷贝构造函数的行为如下:默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.b)如果数据成员是一个数组,对数组的每一个执行按位拷贝.c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.1.深拷与浅拷深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候(复制指针所指向的值),这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源(只复制了指针所指的地址)的情况视为浅拷贝。
浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错,这点尤其需要注意!原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。
浅:using namespace std;//shallow && deep copy//deep copy make pointer point to a new place! class Product...{public:int* pointer;Product(int i=0)...{pointer=new int(i);}//change class variablevoid change(int i)...{*pointer=i;}//deconstructor~Product()...{delete pointer;}};int main()...{Product p1(2);Product p2(p1);p1.change(3);cout<<*p2.pointer<<endl;getchar();return 0;}深:using namespace std;//shallow && deep copy//deep copy make pointer point to a new place! class Product...{public:int* pointer;Product(int i=0)...{pointer=new int(i);}//change class variablevoid change(int i)...{*pointer=i;}// copying constructorProduct(const Product &p)...{pointer=new int(*p.pointer); }//deconstructor~Product()...{delete pointer;}};int main()...{Product p1(2);Product p2(p1);p1.change(3);cout<<*p2.pointer<<endl;getchar();return 0;}2 拷贝构造函数的另一种调用当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调用拷贝构造函数。
例如:#include <iostream>using namespace std;class Date...{int n;public:Date(int i = 0)...{cout << "载入构造函数" << endl;n = i;}Date(const Date &d)...{cout << "载入拷贝构造函数" << endl;n = d.n;}int GetMember()...{return n;}};void Display(Date obj) //针对obj的操作实际上是针对复制后的临时拷贝进行的...{cout << obj.GetMember() << endl;}int main()...{Date a;Date b(99);Display(a); //对象直接作为参数Display(b); //对象直接作为参数getchar();return 0;}程序输出:载入构造函数:载入构造函数:载入拷贝构造函数0载入拷贝构造函数99还有一种情况,也是与临时对象有关的。
当函数中的局部对象被用作返回值,返回给函数调用时,也将建立此局部对象的一个临时拷贝,此时拷贝构造函数也将被调用。
——可是经测试发现情况有异。
代码如下:#include <iostream>using namespace std;class Date...{int n;public:Date(int i = 0)...{cout << "载入构造函数" << endl;n = i;Date(const Date &d)...{cout << "载入拷贝构造函数" << endl;n = d.n;}void Show()...{cout << "n = " << n << endl;}};Date GetClass(void) //函数中的局部对象被用作返回值,按理说应该引用拷贝构造函数...{Date temp(100);return temp;}int main()...{Date a;a.Show();a = GetClass();//这里GetClass()函数中的局部对象被用作返回值a.Show();Date b = GetClass();//这里GetClass()函数中的局部对象被用作返回值b.Show();getchar();return 0;}程序输出:载入构造函数:n = 0载入构造函数:n = 100载入构造函数:n = 100按理第2个和第3个应该输出'载入拷贝构造函数"才对,这个结果与预想的不一样,到底是哪里出问题了呢?注:后来有论坛上的朋友告诉我说这是因为编译器的不同而导致不同的输出。
有人得到这样的输出结果:载入构造函数n = 0载入构造函数载入拷贝构造函数n = 100载入构造函数载入拷贝构造函数n = 100还有人得到这样的输出结果:载入构造函数n = 0载入构造函数载入拷贝构造函数n = 100载入构造函数载入拷贝构造函数载入拷贝构造函数n = 100(用的是vc++)3.3 无名对象现在我们来说一下无名对象。