面向对象历年试卷学习笔记
-
拷贝构造函数参数为什么必须使用类类型对象的引用传递?Student (const Student &t);
如果我们传递的不是引用,那么传递的是一个类对象,由于参数并没有初始化,所以会调用构造函数生成参数的一个对象对参数进行赋值,对参数进行赋值就会调用拷贝构造,而拷贝构造还是会调用构造函数对参数进行初始化。这样会一直递归下去,直到程序崩溃。
-
引用在声明时必须对其初始化,以绑定某个已经存在的变量(或对象),在该引用的生命期内,该绑定不能被更改
正确,应该用在声明是就会被和对象绑定,作为别名存在,不能更改绑定的对象,但一个对象能有很多个别名;指针在声明时可以不指向特定对象,且所指对象也可以更改 -
引用返回的函数,可以返回该函数中值传递的形参变量(或对象)。
考虑对象存在的生命期,值传递的形参是一个临时对象,在函数调用结束后就销毁,引用返回这个对象无意义。
-
在C++程序中,操作符new的功能与calloc函数的功能完全一样。
错误,区别如下:
malloc
分配未初始化的内存。分配的内存必须与free
。释放。
calloc
就像是malloc
用一个常量(0)初始化分配的内存。它需要被释放free
。
new
通过调用构造函数来初始化分配的内存(如果它是一个对象)。分配给内存的内存new
应该释放delete
(反过来调用析构函数)。它不需要您手动指定所需的大小并将其转换为适当的类型。因此,它更现代化,不易出错
-
创建一个C++字符串对象(如:string str;),则sizeof(str)的值等于str.length()的值。其中成员函数length为返回字符串的长度。
sizeof(...):
1.是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
2.功能:获得保证能容纳实现所建立的最大对象的字节大小。由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。
strlen(...):
1.是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组是作为首元素指针。
2.功能:返回字符串的长度,实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符'\0'。返回的长度大小不包括'\0'。
c/c++ strlen(str)和str.length()和str.size()都可以求字符串长度。
其中str.length()和str.size()是用于求string类对象的成员函数
strlen(str)是用于求字符数组的长度,其参数是char*
例子:
1)char* ss = "0123456789";
sizeof(ss)为4,ss是指向字符串常量的字符指针,sizeof 获得的是指针所占的空间,则为4
sizeof(*ss)为1,*ss是第一个char字符,则为1
2)char ss[100] = "0123456789";
sizeof(ss)为100,ss表示在内存中预分配的大小,100*1
strlen(ss)为10,它的内部实现用一个循环计算字符串的长度,直到'\0'为止。
3)int ss[100] = "0123456789";
sizeof(ss)为400,ss表示在内存中预分配的大小,100*4
strlen(ss)错误,strlen参数只能是char*,且必须是以'\0'结尾
4)char[] a={'a','b','c'};
sizeof(a)的值应该为3。
char[] b={"abc"};
sizeof(b)的值应该是4。
若string str={'a','b','c','\0','X'};
那么sizeof(str)为5,strlen(str)为3。
- 对在派生类中调用已经重写过的基类函数需要用 基类类名::函数名()的方法调用,如果未重写可以直接用函数名()调用
- Class成员访问属性默认为private,Struct中是public
- 对象赋值运算和拷贝,赋值是一种运算符,不会产生新的对象,是把对象的值赋值给已有的对象(已经存在的实例);拷贝是一种构造函数会传入对象的值创建新对象(赋值函数不产生新的对象)
- 类的静态成员函数存在全局区,不占用特定对象的存储空间
- 存储空间:
- 代码区
- 全局区(静态区):全局对象、常量
- 动态区:
- 堆区:new
- 栈区:函数调用f()产生,断点(状态)
int a = 0; //全局初始化区 char *p1; //全局未初始化区 main() { int b; //栈 char s[] = "abc"; //栈 char *p2; //栈 char *p3 = "123456"; //123456\0在常量区,p3在栈上 static int c =0; //全局(静态)初始化区 p1 = (char *)malloc(10); //堆 p2 = (char *)malloc(20); //堆 }
https://www.jianshu.com/p/52b5a1879aa1关于栈和堆
- 派生类基类相关:
- 派生类中声明与某基类成员(成员函数、数据成员)同名的成员,同名屏蔽 (override),该成员会屏蔽基类成员,需用基类类名::函数名()的方法调用
- 虚继承,在菱形继承关系中如果不使用虚继承调用A中的成员会产生歧义,因为D中拥有多份从不同路径继承来的A成员变量;虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
- 关于虚基类成员的可见性,在虚基类的最终派生类中只保留一份虚基类成员,所以可以直接访问,但仍会产生问题,以图2中的菱形继承为例,假设 A 定义了一个名为 x 的成员变量,当我们在 D 中直接访问 x 时,会有三种可能性:
- 如果 B 和 C 中都没有 x 的定义,那么 x 将被解析为 A 的成员,此时不存在二义性。
- 如果 B 或 C 其中的一个类定义了 x,也不会有二义性,派生类的 x 比虚基类的 x 优先级更高。
- 如果 B 和 C 中都定义了 x,那么直接访问 x 将产生二义性问题。
- 继承方式
- 公用继承(public inheritance)
基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有(保持不变)。 - 私有继承(private inheritance)
基类的公用成员和保护成员在派生类中成了私有成员,其私有成员仍为基类私有(全是私有)。 - 受保护的继承(protected inheritance)
基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。保护成员的意思是,不能被外界引用,但可以被派生类的成员引用(五五分开)。
- 公用继承(public inheritance)
-
公有继承
(1)采用公用继承方式时,基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性,而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员
(2)要想访问基类的私有成员,只能通过基类的公用成员函数来引用基类的私有数据成员,即在派生类中调用基类的公有成员函数,去访问基类私有数据成员
(3)在类外定义派生类对象,可以访问基类的公有成员,其他成员不可访问
(4)总结:公有继承,派生类内能访问基类的公有,保护成员,不可访问基类私有成员,要访问它,需要通过基类的公有或保护成员函数间接访问;派生类外,派生类对象可访问基类私有成员。
私有继承
(1)私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。一个基类成员在基类中的访问属性和在派生类中的访问属性可能是不同的。
(2)应当注意到,虽然在派生类外不能通过派生类对象调用私有基类的公用成员函数,但可以通过派生类的成员函数调用私有基类的公用成员函数(此时它是派生类中的私有成员函数,可以被派生类的任何成员函数调用)。
(3)总结,私有继承,在派生类内,成员函数能访问基类的公有和保护成员,不可访问基类私有成员,但可以通过基类公有和保护成员函数,间接访问;派生类外,不能访问,要访问,需要在派生类内设计成员函数,该成员函数内,包含基类的成员函数,间接访问。
保护继承
(1)保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。也就是把基类原有的公用成员也保护起来,不让类外任意访问。
(2)保护基类的所有成员在派生类中都被保护起来,类外不能访问,其公用成员和保护成员可以被其派生类的成员函数访问(私有继承都能访问,那么当然这里能访问)。
(3)保护继承与私有继承的区别
在直接派生类中,以上两种继承方式的作用实际上是相同的:在类外不能访问任何成员,而在派生类中可以通过成员函数访问基类中的公用成员和保护成员。但是如果继续派生,在新的派生类中,两种继承方式的作用就不同了。如果以公用继承方式派生出一个新派生类,原来私有基类中的成员在新派生类中都成为不可访问的成员,无论在派生类内或外都不能访问,而原来保护基类中的公用成员和保护成员在新派生类中为保护成员,可以被新派生类的成员函数访问。公用的,派生类内和派生类外都可以访问。
受保护的,派生类内可以访问,派生类外不能访问,其下一层的派生类可以访问。
私有的,派生类内可以访问,派生类外不能访问。
前提条件:不可访问的,派生类内和派生类外都不能访问(即1说明的)。