Nowcoder专项练习:C++(十三)

1,虚基类

设置虚基类的目的是:

  • 消除二义性

多重继承的示例:
在这里插入图片描述

以左侧的图为例:
多重继承的定义:
一个派生类(D)有两个或者两个以上的基类(B和C)

多重继承引发的二义性:
假如上述这些基类(B和C)具有相同的基类A,A中的成员数据和成员函数,最终都会以双份的形式拷贝到类D之中,那么调用它们的时候就会出现二义性的问题。

虚基类:
专门用来解决多重继承继承引发的二义性问题;(可以理解为D直接从A继承)

尽管C++或其他OO语言支持多重继承,但在实际软件开发中多重继承用的并不多,原因在于多重继承过手复杂。因此,在C#中已经不再支持多重继承了。


2,字符数组的复制

  • 字符数组的复制要使用strcpy()函数,不能直接用赋值操作进行赋值。
char a[3], b[]="China";
a = b;
printf("%s", a);

上述的程序段,无法通过编译。


3,分割两个表示符

分号,分割两个句子,加号运算符冒号三目运算符。这些都能分割两个标识符。


4,字符数组问题

Q:
对于下面的代码,输出为?

#include<stdio.h>
 
int main(void)
{
 int n;
 char y[10] = "ntse";
 char *x = y;
 n = strlen(x);
 *x = x[n];
 x++;
 printf("x=%s\n",x);
 printf("y=%s\n",y);
 return 0;
}

A:
在上面的代码中,char *x = y,用指针x指向y的首地址。

n = strlen(x),计算y的元素长度,即4。

*x = x[n],可以理解为:*x = y[4],即将指针x指向y的第五个元素(x[4] = y[4]),又因为前面的char *x = y,y的首地址就换成了y的第五个元素,即’\0’。

因此,之后的输出:

x=ntse
y=

5,内存分配问题

1,malloc,calloc,realloc,free属于C函数库,而new/delete则是C++的操作符;
2,alloc的比较:

  • alloc:唯一在栈上申请内存,无需释放;
  • malloc和calloc的区别是1块与n块的区别和初始化;
  • realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。

6,宏

宏与函数的区别:

  1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型。
  2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.。
  3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的。因此,宏占用的是编译的时间,而函数占用的是执行时的时间。
  4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的。
  5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的。

内联函数与宏的区别:

  1. 内敛函数的运行可以调试,而宏定义不可以。
  2. 编译器会内联函数的参数类型做安全检查或者自动类型转换(如同普通函数),而宏定义则不会。
  3. 内联函数可以访问类的成员变量,宏定义则不能。
  4. 在类中声明同时定义的成员函数,会自动转换为内敛函数。

7,const与成员函数

类的成员函数后面加上const,表明这个函数不会对这个类对象的数据成员(准确的说是费静态数据成员)做任何改变。

常量(即const)对象可以调用const尘缘函数,而不能调用非const修饰的函数。


8,编译预处理命令

编译预处理命令的特点:

  1. 为了区别一般的语句,预处理命令都必须以#开始,结尾处不加分号。
  2. 预处理命名可以放在程序中的任何位置。
  3. 在陈谷汇总凡是以#开始的语句都是预处理命令行。

最常见的预处理有:
文件包含、条件编译、局部控制和宏替换


9,数组指针问题

Q:
若有以下说明和语句,int c[4][5],(*p)[5];p=c;能正确引用c数组元素的是( )。
A. p+1
B. *(p+3)
C. *(p+1)+3
D. *(p[0] + 2)

A:
数组指针,也叫行指针。
定义 int (*p)[n]
其中,()优先级高,因此首先说明p是一个指针,指向一个整型的一维数组,这个数组的长度为n,也可以说是p的步长。即,当执行p+1时,p要跨过n个整型数组的长度。

如要将二维数组赋给一指针,应这样赋值:

int c[4][5];
int (*p)[5];		//该语句是定义一个数组指针,指向含有5个元素的一维数组。
p = c;		//该二维数组的首地址赋给p,也就是c[0]或者&c[0][0]
p++;		 //该语句执行过后,也就是p=p+1;p跨过行c[0][]指向了行c[1][]
*(p[0]+2);		//等价于*(*(p+0)+2),表示a[0][2];

因此,正确答案为D。


10,参数入栈

Q:
函数func的定义如下:
void func(const int& v1, const int& v2)

{
    std::cout << v1 << ' ';
    std::cout << v2 << ' ';
}

以下代码在vs中输出结果为____。
int main (int argc, char* argv[])

{
    int i=0;
    func(++i,i++);
    return 0;
}

A:
C语言中,函数参数入栈的顺序是从右往左
func(++i, i++)可以分解为:
参数 i 先入栈 输出0
然后执行i++ 此时i为1
接着参数 i 先执行++i i 此时为2 后入栈进行输出 2


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值