C++学习(35)

来源:互联网 发布:java web是做什么的 编辑:程序博客网 时间:2024/06/06 08:29

1.  只能使用成员函数重载的运算符有= () [] ->new delete


在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:

(1)一般情况下,单目运算符最好重载为类的成员函数双目运算符则最好重载为类的友元函数。

(2)以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。

(3)类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。

(4)若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。

(5)若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数

(6)当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。

(7)当需要重载运算符具有可交换性时,选择重载为友元函数。

 

2.  enum中:首元素不赋值的话,默认为0;后一个元素不赋值的话比前一个元素大1;

 

3.  C++默认的类型转换是从下到上,就是系统可以把int,float转换成double,但不会把double转换成int,char;

 

4.  一个C/C++编译的程序占用内存:

1)栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等;

2)堆区(heap):由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。与数据结构中的堆是两回事。

3)全局区(静态区)static:全局变量和静态变量的存储是放在一块的,初始化时候全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放;

4)文字常量区:常量字符串放在这里,程序结束后有系统释放;

5)程序代码区:存放函数体的二进制代码;

 

补充:栈由系统自动分配,速度较快;堆是由new分配,速度较慢,易产生内存碎片。但是用起来方便;

 

5.  下面代码运行结果:

#include<iostream>#include<string.h>using namespace std;class B{  public:    B() {     cout<<"defaultcontructor"<<" ";    }    ~B() {     cout<<"destructed"<<"";    }    B(inti):data(i){     cout<<"contructedby parameter"<<data<<" ";    }    private:intdata;};  B play(B b) {    return b;  }int main() {  B temp=play(5);  return 0;}

分析:调用Play函数需要将5隐式类型转换为Play函数中的形参b,会调用B的B(int i): data(i),打印“constructed by parameter5”。Play函数返回时需要调用B的复制构造函数给对象temp初始化。Play函数返回后需要调用b的析构函数,将Play函数的形参释放,打印“destructed”。main函数返回后需要释放temp,打印“destructed”。

 

分析二:

1).调用Play函数时,会将5隐式的转换为形参b的类型,会调用B的B(int i):data(i),打印”constructed by parameter5“

2).Play函数返回时,temp调用B的默认浅拷贝构造函数,完成赋值,由于拷贝构造函数没有输出,所以没有打印东西

3).Play函数返回后,调用b的析构函数,输出”destructed“

4).main函数返回,调用temp的析构函数,输出”destructed“

 

6.  口诀:左数又指。当const出现在*号左边时,指针指向的数据为常量;当const出现在*号右边时,指针本身为常量。

 

 

7.  C++中,为了让某个类只能通过new来创建(即如果直接创建对象,编译器将报错),应该:将析构函数设为私有

 

分析:编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈(静态)上了,只能在堆上(动态new)分配类对象

点击打开链接


8.

dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,即会作一定的判断。对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。

 

reinterpret_cast这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现。

 

static_cast静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。

 

const_cast这个转换好理解,可以将常量转成非常量。

 

9.回调函数,就是预先在系统的对函数进行注册,让系统知道这个函数的存在,以后,当某个事件发生时,再调用这个函数对事件进行响应。定义一个类的成员函数时在该函数前加CALLBACK即将其定义为回调函数,函数的实现和普通成员函数没有区别。

 

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

核心就是类成员函数需要this指针访问函数,而全局或者静态函数不需要this指针。

简言之,类的成员函数需要隐含的this指针,而回调函数没有办法提供。

 

10.程序输出:1 2 15

#include<iostream>#include<string.h>using namespace std; int main() {  short *p,*q;  short arr[15]={0};  p=q=arr;  p++;  cout<<p-q<<"";  cout<<(char*)p-(char *)q<<" ";  cout<<sizeof(arr)/sizeof(*arr);  return 0;}

分析:指针自增、自减每次移动的偏移量是指针所指向对象的字节大小,所以p++与q的偏移量是2个字节。

指针相减的值是指针地址的偏移除以指针每次移位的大小;

1)p-q=1;偏移量为2个字节,每次移动2个字节,所以为1

2)(char *)p-(char *)q,指针的偏移没变,但是每次指针移位是按照(char*)类型移动,即每次移动1个字节,所以是2

3)数字每次元素2个字节,所以sizeof(arr)为30,sizeof(*arr)为2。

 

分析二:整体求解思路是:p q是指向地址的指针,随着数据类型的不同而产生的偏移量不同;short类型大小是2字节,char类型大小是1字节; ++p是地址偏移量为2字节,但是对于short类型来说就是相差1,转化为char类型就是2;sizeof是指数组的所占内存的大小=数据类型*个数;

 

11.C++规定,重载运算符必须和用户定义的自定义类型对象一起使用。

MyClass operator *(double,MyClass);

MyClass operator *(MyClass,MyClass);

MyClass operator *(MyClass,double);

对于一个运算符函数来说,它或者是类的成员,或者至少包含一个类类型参数。操作符重载允许将标准C++操作符用于类对象;

 

12.A选项:在组合类的析构函数中并不需要显式调用其成员对象的析构函数,因为当执行组合类的析构函数时,其数据成员也会被销毁,对于类成员对象来说,成员对象销毁时,程序会自动调用其析构函数;不过对于组合类中new的指向类成员的指针,组合类需要自己去delete该指针;

 

B选项:显然是错的,在类继承层次中,基类在上,派生类在下,所以可以自动进行向上类型转换,即可以使基类指针和引用指向派生类对象,而不可以使派生类指针和引用指向基类对象;

C选项:对的,构造函数可以根据参数的不同实现函数重载,而析构函数没有参数,对于一个类来说也是唯一的,所以是不能重载的;

D选项:即派生类想要重写继承来的成员函数,需要用到virtual函数,来实现动态多态。

原创粉丝点击