C++学习(41)

1.  源码->(扫描)->标记->(语法分析)->语法树->(语义分析)->标识语义后的语法树->(源码优化)->中间代码->(代码生成)->目标机器代码->(目标代码优化)->最终目标代码。


2.  源代码-->预处理-->编译-->优化-->汇编-->链接-->可执行文件

汇编阶段把 汇编语言代码/中间代码 翻译成目标机器指令。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。(代码生成阶段)

 

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

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


基础概念:

回调函数就是一个通过函数指针调用的函数。

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

 

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

 

3.  本题考查字符串处理函数 strlen 、 strcat 、 strcmp 。 B选项中 strlen 返回的是字符串 s 实际占用内存大小加上结尾符, A 选项中不能用关系运算符进行大小比较,可以使用 strcmp 。 D 选项当使用连接函数 strcat 时,内存空间会减少一个字符位置。

 

4.  友元函数重载时,参数列表为1,说明是1元,为2说明是2元;

成员函数重载时,参数列表为空,是一元,参数列表是1,为2元;

 

5.  C++对空类或者空结构体,对其sizeof操作时候,默认都是1个字节;

 

6.  const void print(constint num)const

第一个const修饰返回类型;第二个const修饰参数;第三个const修饰调用对象;

 

7.  x是方法参数,则x的值和它所在的内存位置,都会在方法结束后失效,所以, 指针p不应该指向x的内存地址,而应该指向自己申请的一个地址空间,于是D错;而至于B和C,为何选B,由于 ‘p’和‘*p’,一个表示p指向的地址,一个则表示p指向的地址位置的值,所以,p = new int(x); 大致做了两件事:① 让p指向一个不会由于方法结束而失效的地址②将x值传给这个地址空间处, 所以最终,*p 也就是 p指向位置的值,就是x值。最终,选B。

 

8.  关键是区分 浅/深拷贝操作和 赋值操作:没有重载=之前:

A a ;

A b;

a = b;

这里是赋值操作。

A a;

A b = a;

这里是浅拷贝操作。

 

重载 = 之后:

A a ;

A b;

a = b;

这里是深拷贝操作(当然这道题直接返回了,通常我们重载赋值运算符进行深拷贝操作)。

A a;

A b = a;

这里还是浅拷贝操作。

 

所以MyClass obj3 = obj1; 调用的是拷贝构造函数。

如果写成MyClass obj3;obj3 = obj1; 输出的结果就是1203444

 

9.分析下列程序:

#include<iostream>
using namespace std;
void test (void *data){
  unsigned int value=*(unsigned int*)(data);
  printf("%u",value);
}
int main() {
  unsigned int value =10;
  test(&value);
  return 0;
}

分析:注意void test(void *data);此处参数类型是void,所以先要进行指针转换:(unsigned int *)然后再取值。

参数是void*,编译器不知道它的具体数值类型,不能直接取值,先转换为具体指针类型,然后再取值。


实际上只要是*data,我们就知道了它是指针,如果是32位机器,该指针就指着内存中的某个地址,用32位表示,记住这个32位只是初始地址,任何指针都是的。而前面的void 或者int 类型是定义一次读几个字节,如果是int则读4个字节,也就是从*data存的地址开始从内存往后读4个字节就行,而void是空,没有指定要读多少个字节,所以要用指针类型(unsigned int *)强制转化为知道要读几个字节的int指针,然后再用*从开始地址,读取unsigned int个字节出来!

 

10.||是逻辑或,只要一边为真,表达式的值就是真。(造成短路现象)

 

11.抽象类之所以不能被实例化,是因为它里面是抽象方法,实例化对象调用其里面的方法没有意义,我们需要做的就是覆写掉里面的抽象方法。而这个抽象方法其实就是纯虚函数,通过派生类来override纯虚函数,定义N个方法。

使用纯虚函数的意义是很多情况下,基类本身生成对象是不合情理的。

 

12

1)b.FuncA();输出

FuncA called

    FuncABcalled

2)b.FuncB();输出

   FuncBBcalled

上两者好理解,直接调用类B的成员函数

3)pa->FuncA();输出

  FuncA called调用类A的FuncA()

4)pa->FuncB();输出

FuncBB called调用类B的FuncB(),原因是C++的动态决议机制,当基类函数声明为virtual时,指向派生类对象的基类指针来调用该函数会选择派生类的实现,除非派生类没有才调用基类的虚函数。还有一点注意的是:指向基类类型的指针可以指向基类对象也可以指向派生类对象,如pa=&b;

5)pa2->FuncA(); pa2->FuncB();输出

  FuncA called

  FuncB called

这也好理解,直接调用类A的相应成员函数。

 

父类指针指向子类实例对象,调用普通重写方法时,会调用父类中的方法。而调用被子类重写虚函数时,会调用子类中的方法。再次说明了,子类中被重写的虚函数的运行方式是动态绑定的,与当前指向类实例的父类指针类型无关,仅和类实例对象本身有关


只有虚函数的成员函数才进行动态绑定,成员函数认为非虚函数,非虚函数不进行动态绑定。

 

13. C、静态函数不可以是虚函数

因为静态成员函数没有this,也就没有存放vptr的地方,同时其函数的指针存放也不同于一般的成员函数,其无法成为一个对象的虚函数的指针以实现由此带来的动态机制。静态是编译时期就必须确定的,虚函数是运行时期确定的


D虚函数可以声明为inline

inline函数和virtual函数有着本质的区别,inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够确定如何去调用的,因而inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。

因此,内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的。

函数的inline属性是在编译时确定的,然而,virtual的性质则是在运行时确定的,这两个不能同时存在,只能有一个选择,文件中声明inline关键字只是对编译器的建议,编译器是否采纳是编译器的事情。

我并不否认虚函数也同样可以用inline来修饰,但你必须使用对象来调用,因为对象是没有所谓多态的,多态只面向行为或者方法,但是C++编译器,无法保证一个内联的虚函数只会被对象调用,所以一般来说,编译器将会忽略掉所有的虚函数的内联属性。

 

相关知识点:什么函数不能声明为虚函数

一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的。

设置虚函数须注意:

1只有类的成员函数才能说明为虚函数

2:静态成员函数不能是虚函数;

3:内联函数不能为虚函数;

4:构造函数不能是虚函数;

5:析构函数可以是虚函数,而且通常声明为虚函数。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值