C++知识总结

1.C++面向对象三大特征:继承、封装、多态。其中多态分为静态多态和动态多态。静态多态:重载,参数模板 动态多态:虚函数,强制转换。
2.static类型的变量存在静态存储区,初始值为0或者null
3.char *p=“PCGAME” ,是定义初始化指针变量,指针变量的值是一个字符串的首地址
4.已知int a[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };,不能表示数组元素a[2][1]的地址是()

解析:
A:a[2][1] 表示变量本身,&a[2][1]表示取该变量的地址
B:a[2]表示一个指针,它指向a[2][0],a[2]+1则指向的是a[2][1]变量,所以*(a[2]+1)表示的是a[2]+1所指向单元的内容,即a[2][1]
C:a[2]+1仍然是指针,指向的还是a[2][1]的地址
D:a也是指针,而它指向的是a[0],指向的还是指针,a+2指向的是a[2]这个指针,所以*(a+2)是指针a[2]本身,*(a+2)+1=a[2]+1

5.下面四个选项中,均是不合法的浮点数的选项是()
A: 160. 0.12 e3
B:123 2e4.2 .e5
C:-.18 123E4 0.0
D:-e3 .234 1e3

解析:
C语言中的浮点数有两种形式,一种为十进制小数形式,一种为指数形式。其一般形式为a E n,a为十进制整数,n为十进制数,都不可省略,
A:e3是非法的,前面没有十进制数
B:123 是整数,不是浮点数,2e4.2,e后边的数字必须为整数,.e5 不能只有小数点没有数字
C:均合法
D:-e3不合法

6.不考虑任何编译器优化(如:NRVO),下述代码的第10行会发生

#include <stdio.h>
class B{
};
B func(const B& rhs){
  return rhs;
}
int main(int argc, char **argv){
  B b1, b2;
  b2 = func(b1);  //10
}
解析:
一次拷贝构造函数,一次析构函数,一次(拷贝赋值运算符)

1.一次拷贝构造函数发生在func函数调用完成,返回B类型的对象时,因为返回的不是引用类型,所以会生成一个对象,不妨称为TEMP,将返回的对象通过拷贝构造函数复制给TEMP,由于拷贝构造函数的参数是const B&,rhs并不会在函数结束时候被析构,这时并不调用析构函数;
2.赋值运算符在func函数执行完成后,将上面提到的TEMP,通过赋值运算符赋值给b2;
3.这句表达式的最后将临时对象TEMP进行析构;

7.关于c++的inline关键字,以下说法正确的是()
A:使用inline关键字的函数会被编译器在调用处展开
B:头文件中可以包含inline函数的声明
C:可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数
D:定义在Class声明内的成员函数默认是inline函数
E:优先使用Class声明内定义的inline函数
F:优先使用Class实现的内inline函数的实现

解析:
A 项错误,因为使用 inline 关键字的函数只是用户希望它成为内联函数,但编译器有权忽略这个请求,比如:若此函数体太大,则不会把它作为内联函数展开的。

B 项错误,头文件中不仅要包含 inline 函数的声明,而且必须包含定义,且在定义时必须加上 inline 。【关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用】

C 项错误, inline 函数可以定义在源文件中,但多个源文件中的同名 inline 函数的实现必须相同。一般把 inline 函数的定义放在头文件中更加合适。

D 项正确,类内的成员函数,默认都是 inline 的。【定义在类声明之中的成员函数将自动地成为内联函数】

EF 项无意思,不管是 class 声明中定义的 inline 函数,还是 class 实现中定义的 inline 函数,不存在优先不优先的问题,因为 class 的成员函数都是 inline 的,加了关键字 inline 也没什么特殊的。

8.已知int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, *p = a;,不能表示数组a中元素的式子是()
A:*a
B:*p
C:a
D:a[p-a]

解析:C
选项A和B应该问题不大,对数组名进行操作时数组名会退化为常量指针指向数组的首元素地址,*p和*a的值都是数组首元素的值。
对于C选项:前面已经解释过了,a就是一个指向数组首元素地址的指针,a表示的是一个地址不是数组中的元素
对于D选择,其实也可以根据前面的解释知道结果了,由于*p=a;所以p和a都是指向数组首元素地址的指针,即p和a是相等的,所以p-a=0,也就是a[p-a]=a[0].

9.以下程序的输出结果(32位机器上)是()

int main(){ 
    char *p = "abcdefgh", *r;
    long *q;
    q = (long*)p;
    q++;
    r = (char*)q;
    printf("%s\n", r);
}

A:abcd
B:bcde
C:cdef
D:efgh

解析:D
char* p = "abcdefgh",每个字符占1个字节,那么总共是8个字节,此时p指向'a'。如果是p++,那么p将指向'b'。打印p会得到"bcdefgh"。

long* q = (long*)p 将p强制转换为long*类型,也就是用long类型去解释存储了"abcdefgh"的这一段内存,此时q指向'a',由于long类型是4个字节,那么q++移动4个字节,q将指向'e',打印q将得到"efgh"

10.有如下C++代码:

struct A{
  void foo(){printf("foo");}
  virtual void bar(){printf("bar");}
  A(){bar();}
};
struct B:A{
  void foo(){printf("b_foo");}
  void bar(){printf("b_bar");}
};

那么

A *p = new B;
p->foo();
p->bar();

输出为:barfoob_bar

解析:A *p=new B //A的指针指向B对象
当执行new B时,调用B的无参构造函数,由于B继承A,所以首先调用A的构造函数,在A的构造函数中调用虚函数bar(),这时调用的是A的bar函数,输出内容为bar。如果在构造函数或析构函数中调用虚函数,则运行的是本人类型定义的版本,因为构造子类的时候,首先回去调用父类的默认构造函数,此时子类还是未初始化的,所以不可能调用子类函数。基类中若有虚函数调用派生类的函数,若不是虚函数调用基类的函数。
p->foo() 因为foo不是虚函数,所以执行的是父类A的foo函数
p->bar() 因为bar是虚函数,所以执行的是子类B的bar函数

11.关于构造函数描述:
对象创建时调用构造函数,函数名与类名必须相同。可以带参数和重载,但是不能有返回值。
对象撤销时调用析构函数,名称固定,类名前加~,不带参数和重载,也不能有返回值。
12.sizeof和strlen

void Func(char str_arg[100]){
    printf("%d\n", sizeof(str_arg));
}
int main(void){
    char str[] = "Hello";
    printf("%d\n", sizeof(str));
    printf("%d\n", strlen(str));
    char*p = str;
    printf("%d\n", sizeof(p));
    Func(str);
}

32位系统下下面程序的输出结果为多少?

输出结果为:6 5 4 4
对字符串进行sizeof操作的时候,会把字符串的结束符"\0"计算进去的,进行strlen操作求字符串的长度的时候,不计算\0的。
数组作为函数参数传递的时候,已经退化为指针了,Func函数的参数str_arg只是表示一个指针,那个100不起任何作用的.

13.有如下程序段:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void GetMemeory(char *p) {
    p = (char *)malloc(100);
}

void Test() {   
    char *str = NULL;
    GetMemeory(str);
    strcpy(str, "Thunder");
    strcat(str + 2, "Downloader");
    printf(str);
}

请问运行Test函数结果是:程序崩溃

解析:
1.str作为一个指针,但实际为int类型,传入函数内部并不会发生任何改变
2.GetMemory函数执行完成后,str仍然指向NULL,所以赋值时会崩溃
3.正确的做法应该使用双指针

正确的代码如下:

void GetMemory(char **p){
    *p = (char *)malloc(100);
}

void Test(){
    char *str = NULL;
    GetMemory(&str);
    strcpy(str,"Thunder");
    strcat(str+2,"Downloader");
    printf(str);
}

解析:如果要改变实参的值,就传递实参的地址。这里指针作为实参,所以要传递指针的地址

14.设:char w; int x; float y; double z; 则表达式: w*x+z-y 值的数据类型是()

解析:float类型
c++中由低级向高级进行转换,int float double

15.以下程序的输出是:

#include <iostream>
using namespace std;
template <typename T>
void print(T t){
    cout<<"The value is "<<t<<endl;
}
template <>
void print<char *>(char* c){
    cout<<"The string is " << c <<endl;
}
int main(){
    char str[] = "TrendMicro[char]";
    unsigned char ustr[] = "TrendMicro[unsigned char]";
    print(str);
    print(ustr);
    return 0;
}
解析:输出的结果是
The string is TrendMicro[char]<br>The value is TrendMicro[unsigned char]
模板也是有优先级的,特例化模板优先匹配特例化模板  

16.如下程序用于输出“Welcome to Huawei Test”,请指出其中潜在风险的位置()

char * GetWelcome(void){
    char * pcWelcome;
    char * pcNewWelcome;
    pcWelcome = "Welcome to Huawei Test";
    pcNewWelcome = (char *)malloc(strlen(pcWelcome));    //1
    if(NULL == pcNewWelcome){
        return NULL;        //2
    }
    strcpy(pcNewWelcome, pcWelcome);    //3
    return pcNewWelcome;            //4
}
printf("%s\n", GetWelcome());

17.有下列类定义

#include<iostream>
using namespace std;
class Point {
public:
    Point(int a=3,int b=5){ X=a;Y=b;}
    int GetX(){return X;}
    int GetY(){return Y;}
private:
    int  X,Y;
};

现有语句Point *p=new Point[2];则与(*p).GetX()等效的表达式是( )?

解析:p[0].GetX()和p->GetX()
->主要用于类类型的指针访问类的成员
.主要用于类类型的对象访问类的成员

18.在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用

解析:
False,这种说法是错误的,可以通过作用域运算符“::”可以访问全局变量。 全局变量和局部变量并不冲突。

19.下面程序的输出结果是()

#include <stdio.h>
int main() { 
    int  intArray[] = {1, 2, 3, 4, 5}; 
    int  *p = (int *)(&intArray+1); 
    printf("%d,%d",*(intArray+1),*(p-1)); 
    return 0; 
}
正确答案为2,5
*(intArray+1)其实很简单就是指intArray[1],输出为2.
问题关键就在于第二个点,*(p-1)输出为多少?
解释如下,&intArray+1不是首地址+1,系统会认为加了一个整个intArray数组,偏移了整个数组intArray的大小(也就是5个int的大小)。所以int*p=(int*)(&intArray+1);其实ptr实际是&(intArray[5]),也就是intArray+5.
原因为何呢?

&intArray是数组指针,其类型为int(*)[5];

而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同,intArray是长度为5的int数组指针,所以要加5*sizeof(int),所以p实际是intArray[5],但是p与(&intArray+1)类型是不一样的,这点非常重要,所以p-1只会减去sizeof(int*),intArray,&intArray的地址是一样的,但意思就不一样了,intArray是数组首地址,也就是intArray[0]的地址,&intArray是对象(数组)首地址,intArray+1是数组下一元素的地址,即intArray[1],&intArray+1是下一个对象的地址,即intArray[5]。

20.对于下面char (*p)[16]的声明描述正确的一项是()

解析:
p是指向长度为16的字符数组的指针
char (*p)[10];代表了一个指针,这个指针是指向一个大小为10的字符数组;
需要与char *p[10];区分开来,这个代表了一个大小为10的数组,数组的每个元素都是一个字符指针。

21.对于下面代码段,正确的赋值语句( )
A:p=“abcd”;
B:a=“abcd”;
C:*p=“abcd”;
D:*a=“abcd”;

解析:A
A:p是字符型指针,将“abcd”的的地址给了p,也就是p指向字符串“abcd”的首地址,也就是指向‘a’的地址。
B:a是字符数组的地址,不可赋值。
C:*p是一个字符,不能给其赋值字符串
D:同上

22.下列关于 C++ 构造函数的说法,错误的是()
A:构造函数不可以是私有的(private)
B:一个类中可以有多个构造函数
C:无论何时,只要类的对象被创建,就会执行构造函数
D:构造函数没有返回类型

解析:A
A:构造函数可以是私有的,这样能对外界构造类对象进行限制(比如单例模式的一种实现)。
B:类根据构造函数参数个数不用,可以有多个构造函数,比如拷贝构造函数、移动构造函数等。
C:对象在创建时必定会执行构造函数。
D:因为构造函数的特殊性,C++ 构造函数没有返回值,因此也没有返回值类型。

23.有代码如下所示,则在执行 delete p 时,控制台会输出什么内容()

class Base
{
     public:
         virtual ~Base(){
         	std::out<<"Base Destructor"<<std::endl;
       	}
}
class Derived: public Base
{
    public :
        ~Derived(){
        	std::out<<"Derived Destructor"<<std::endl;
        }
}
Base* p=new Derived();
delete p;

A:Base Destructor
B:Derived Destructor
C:Base Destructor
Derived Destructor
D:Derived Destructor
Base Destructor

解析:正确答案是D
关于构造函数、析构函数 基类和派生类的解释
在创建派生类对象时,构造函数的执行顺序和继承顺序相同,即先执行基类构造函数,再执行派生类构造函数
而销毁派生类对象时,析构函数的执行顺序和继承顺序相反,即先执行派生类析构函数,再执行基类析构函数
如果基类的虚构函数是虚函数,delete基类的指针时,会先调用派生类的析构函数,然后调用基类的析构函数。如果基类的虚构函数不是虚函数,销毁的时候会只调用基类的析构函数,而不调用派生类的析构函数。

24.请找出下面程序中有哪些错误:

int main(){
   int i = 10;
   int j = 1;
   const int *p1;//(1)
   int const *p2 = &i; //(2)
   p2 = &j;//(3)
   int *const p3 = &i;//(4)
   *p3 = 20;//(5)
   *p2 = 30;//(6)
   p3 = &j;//(7)
return 0;
}

A:1,2,3,4,5,6,7
B:1,3,5,6
C:6,7
D:3,5

解析:正确答案C
1.如果关键字const出现在星号左边,表示被指物是常量。
2.如果出现在星号右边,表示指针自身是常量。
3.如果出现在星号两边,表示被指物和指针两者都是常量。
int main(){
   int i = 10;
   int j = 1;
   const int *p1;//(1) const在星号的前边,表示被指物是常量,而指针不是常量,可以不必初始化。
   int const *p2 = &i; //(2)const在星号的前边,被指物是常量,而指针不是常量,初始化p2等于取i的地址
   p2 = &j;//(3) p2取的是j的地址,指针可以进行变化
   int *const p3 = &i;//(4) const在星号的后边,所以指针是常量,必须初始化,这里初始化为i的地址,不允许被修改
   *p3 = 20;//(5)ok 可以修改指针p3指向的内容
   *p2 = 30;//(6)错误 指针指向的内容不可以改变
   p3 = &j;//(7)错误 指针是常量不能够进行修改
return 0;
}

25.64位系统下有‘char **p[4]’ 请问’sizeof p’的值是多少?

解析:
正确答案 32
指针的指针还是指针,64位指针的大小为8  4*8=32

26.C++中struct和class的区别:struct的成员默认是公有的,class的成员默认是私有的
27.继承是面向对象的三个特点之一,下列关于继承特点的说法正确的有:
在这里插入图片描述
28.int Func(int,int);不可与下列哪个函数构成重载
A:int Func(int,int,int);
B:double Func(int,int);
C:double Func(double,double);
D:double Func(int,double);

解析:
正确答案:B
重载除了看函数同名以外,主要看的是形参的个数,类型以及顺序。

29.int a[10] = {2,3,5}, 请问a[3]及a[3]之后的数值是()

解析:
答案是0
1、未初始化的全局数组为0;
2、未初始化的局部数组为随机值;
3、初始化部分的全局数组与局部数组,初始化部分为初始化值,未初始化部分都为0;(不管全集还是局部)

30.使用重载函数的目的是(使用相同的函数名调用功能相似的函数)

解析:函数重载:以不同参数列表定义的具有相同函数名的一系列函数用以实现相似的功能。

31.赋值操作是从右向左操作
32.

#include <stdio.h>
int fun(int a) {
    int b = 0;
    static int c = 3;
    b++;
    c++;
    return (a+b+c);
}

int main( ) {
    int i=0;
    for(; i < 3; i++)
        printf("%d",fun(2));
    return 0;
}
解析:789
注意题目中的static关键字,声明静态局部变量时该局部变量会暂时保存到内存的静态区(所以即使这个函数结束运行,这个静态值还是不会被销毁,函数下次使用时依然用到这个值)

33.class类默认的是private,不可以通过对象进行访问,struct结构体默认的是public。
34.strcpy是复制函数 strcat是拼接函数
35.以下对于枚举类型的定义正确的是:()

A:enum a={one,two,three};
B:enum a{a1,a2,a3};
C:enum a={'1','2','3'};
D:enum a{"one","two","three"};
解析:B
枚举在C/C++/C#中,是一个被命名的整型常数的集合。所以D中的双引号元素字符串集合错误。

36.有以下一段代码:

class A
{
public:
    A()
    {
        printf("A");
    }
    ~A()
    {
        printf("~A");
    }
    void B()
    {
        printf("B");
    }
};
int main()
{
    A* a = (A*)malloc(sizeof(A));
    a->B();
    free(a);
    return 0;
}

请问程序最后的输出结果:
A: A
B: ~A
C: B
D: AB~A

解析:C  new/delete  malloc/free的区别 new/delete new是首先调用构造函数,delete调用析构函数。但是malloc不会调用构造函数。

37.下列关于静态成员和非静态成员的函数说法正确的是():
A:静态成员存在于内存,非静态成员需要实例化才会分配内存
B:非静态成员可以直接访问类中静态的成员
C:静态成员能访问非静态的成员
D:非静态成员的生存期决定于该对象的生存期,而静态成员生存期则与程序生命期相同

解析:静态成员存储在内存,非静态成员必须实例化之后才会分配内存,所以静态成员函数不能访问非静态的成员。因为静态成员存于内存,所以非静态成员函数可以直接访问类中的静态成员。

38.关于虚函数与纯虚函数的说法:https://www.runoob.com/w3cnote/cpp-virtual-functions.html

1.被virtual关键字修饰的成员函数,就是虚函数
2.在基类中实现纯虚函数的方法是在函数原型后加"=0",virtual void funtion1()=0
3.使用纯虚函数的意义是在很多情况下,基类本身生成对象是不合情理的

39.如果x=2014,下面函数的返回值是()

int fun(unsigned int x){
     int n = 0;
     while(x + 1){
         n++; 
         x = x | (x + 1);
     }
     return n;
}
解析:
返回值为:23
2014对应的二进制为:0000 0000 000 0000 0000 0111 1101 1110
而x|(x+1)的作用是对一个数中二进制0的个数进行统计
例如本题:
第一次循环:0000 0000 000 0000 0000 0111 1101 1110 |0000 0000 000 0000 0000 0111 1101 1110 =0000 0000 000 0000 0000 0111 1101 1111
第二次循环:0000 0000 000 0000 0000 0111 1101 1111 |0000 0000 000 0000 0000 0111 1110 0000 =0000 0000 000 0000 0000 0111 1111 1111
.
.
每循环一次0的数量减一 ,直到溢出 
所以2014二进制中一共有23个0则返回值为23

x&(x-1)统计1的个数,x|(x+1)统计0的个数

40.int (s[10])(int) 中s表示的是什么?
A.指针数组,每个指针指向长度为1的int数组
B. 指针数组,每个指针指向长度为10的int数组
C. 函数指针数组,每个指针指向一个int func(int
param)的函数。
D.函数指针数组,每个指针指向一个int func(int param)的函数。

解析:D
1.首先第一个int为函数的返回类型为int
2.首先*s[10]是一个指针数组,s是一个含有10个指针的数组,故可以这样来看这条声明语句:假设p等价于s[10],声明语句就变为int(*p)(int);
3.观察int(*p)(int),从名字开始,p前面有一个*,因此p是指针,右侧是形参列表,表示p指向的函数,再观察左侧函数返回的是int;
4.则int(*p)(int) 解读为:函数指针,指向一个int  func(int param)的函数
5.故int(*s[10])(int):解读为:函数指针数组,每个指针执行一个int func(int param)的函数

41.能够把指定长度的字节序列插入到输出流中的函数是()
A.put
B.write
C.cout
D.print

解析:B

42.有如下代码:

struct A1{
    virtual ~A1(){}
};
struct A2{
    virtual ~A2(){}
};
struct B1 : A1, A2{};
int main()
{
 B1 d;
 A1* pb1 = &d;
 A2* pb2 = dynamic_cast<A2*>(pb1);  //L1
 A2* pb22 = static_cast<A2*>(pb1);  //L2
 return 0;
}

L1语句编译通过,L2语句编译失败

解析:
dynamic_cast是通过“运行时类型检查”来保证安全性的。
dynamic_cast 专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。
static_cast 用于进行比较“自然”和低风险的转换,如整型和浮点型、字符型之间的互相转换。另外,如果对象所属的类重载了强制类型转换运算符 T(如 T 是 int、int* 或其他类型名),则 static_cast 也能用来进行对象到 T 类型的转换。

43.要求用成员函数重载的运算符是()
A.=
B.==
C.<=
D.++

解析:A
只能使用成员函数重载的运算符有:=、()、[]、->、new、delete。
ClassA *pclassa=new ClassA[5];
delete pclassa;

c++语言中,类classA的构造函数和析构函数的执行次数分别为(5,1)

解析:ClassA *pclassa=new ClassA[5];new了五个对象,所以构造五次,然后pclassa指向这五个对象,delete pclassa;析构一次,delete[] pclassa 这样就析构了五次。

TIPS:该题主要是考察delete和delete[]的区别

45.关于c++拷贝构造函数说法正确的是()
1.产生了新的对象实例,调用的就是拷贝构造函数;如果没有,调用的是赋值运算符
2.没有定义拷贝构造函数的话,编译器会默认自动产生拷贝构造函数
3.类中可以存在超过一个拷贝构造函数
4.声明一个私有拷贝构造函数可以防止按值传递对象

46.64位电脑运行c++结果输出()

#include <iostream>
using namespace std;

class A {
    char a[2];
public:
    virtual void aa() {};
};

class B : public virtual A {
    char b[2];
    char a[2];
public:
    virtual void bb() {};
    virtual void aa() {};
};

class C : public virtual B {
    char a[2];
    char b[2];
    char c[2];
public:
    virtual void cc() {};
    virtual void aa() {};
    virtual void bb() {};
};

int main() {
    cout << sizeof(A) << endl << sizeof(B) << endl << sizeof(C);
    return 0;
}

子类的空间 = 子类的成员所占空间(补齐) + 一个虚函数指针所占空间(不论有几个虚函数都只分配了一个指针) + 父类所占空间;

结构体(struct):比较复杂,对齐问题。
然而,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:

(1)结构体变量中成员的偏移量必须是成员自身大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员的整数倍,也即所有成员大小的公倍数。(另一个名字叫 补齐)或者说最大成员
注意:在计算对齐和补齐时,LINUX中成员超过4字节按4字节计算,而WINDOWS系统按规定计算

联合(union):所有成员中最长的。

枚举(enum):根据数据类型。

三、sizeof计算嵌套的结构体大小
对于嵌套的结构体,需要将其展开。对结构体求sizeof时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大成员的整数倍。
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。

原文链接:https://blog.csdn.net/weixin_42073412/article/details/100150103

解析:16 32 48
对于对象A,包含一个虚函数指针,虚函数指针的sizeof为8。第一个2,补至8,再加8等于16
对于对象B,检测到虚继承于A,两个char 2, 两个char 2, 补齐4个,2+2+4+8(虚函数指针)=16+sizeof(A)=32
对于对象C,检测到虚继承B, 两个char 2, 两个char 2, 两个char 2,补齐2个 2+2+2+2+8(虚函数指针)=16+sizeof(B)=48

47.以下哪一些是C++的属性(非C的属性)
c++属性:class、 template、virtual function

#pragma指示使每个编译程序在保留C和C++语言的整体兼容性时提供不同机器和操作系统特定的功能。
union 是一种特殊的类, C与C++中都可以使用

48.下列能对二维数组a进行正确初始化的语句是()
A.int a[2][ ]={{1,0,1},{5,2,3}};
B.int a[ ][3]={{1,2,3},{4,5,6}};
C.int a[2][4]={{1,2,3},{4,5},{6}};
D.int a[ ][3]={{1,0,1},{},{1,1}};

解析:B
定义二维数组并赋初值时,可以省略第一维的大小,但是不能省略第二维的大小,所以A错,C超出了初始化的下角标,D其中有一行是空行。所以只能选B

49.阅读下面 C++ 代码,输出结果为()

#include <iostream>
using namespace std;

class base1 {
private: int a, b;
public:
    base1(int i) : b(i + 1), a(b) {}
    base1():b(0), a(b) {}
    int get_a() { 
        return a; 
    }
    int get_b() { 
        return b; 
    }
};
int main() {
    base1 obj1(11);
    cout << obj1.get_a() << " " << obj1.get_b() << endl;
    return 0;
}

A.12 12
B.随机数 12
C.随机数 随机数
D.12 随机数

解析:B
初始化列表的初始化顺序按照成员的声明顺序而来。int a,b; 因此obj(11)是先初始化a,但是a的值由b决定,b此时没有初始化,因此为随机值.然后初始化b为12.因此选择B选项

50.执行以下语句,输出的结果为:

#include<stdio.h>
int main( ) {
char *p1 = "hello";
char *p2 = "world";
char *p3 = "a piece of cake";
char *str[] = {p1, p2, p3};
printf("%c", *(str[0] + 1));
}

A.world
B.hello
C.编译时错误
D.其他选项都不正确

解析:D
str[0]为p1,p1指向的是“hello”,p1指针+1前进一个指向字符e。最后输出e

51.以下程序在32位机器上运行输出是:

#include<iostream>
using namespace std;
class animal
{
protected:
    int age;
public:
    virtual void print_age(void) = 0;
};
class dog : public animal
{
public:
       dog() {this -> age = 2;}
       ~dog() { }
       virtual void print_age(void) 
       {
           cout<<"Wang, my age = "<<this -> age<<endl;
       }
};
class cat: public animal
{
public:
    cat() {this -> age = 1;}
    ~cat() { }
    virtual void print_age(void) 
    {
        cout<<"Miao, my age = "<<this -> age<<endl;
    }
};
int main(void)
{
    cat kitty;
    dog jd;
    animal * pa;
    int * p = (int *)(&kitty);
    int * q = (int *)(&jd);
    p[0] = q[0];
    pa = &kitty;
    pa -> print_age();
    return 0;

}

A.Wang, my age = 2
B.Wang, my age = 1
C.Miao, my age = 2
D.Miao, my age = 1
E.程序编译报错
F.程序运行报错

解析:B
1.函数只要有virtual,我们就需要吧它添加进vTable
2.每个类都有自己的虚表,因此vTable就变成了vTables
3.虚表存放的位置一般存放在模块的常量段中,从始至终都只有一份。
4.通过(int*)可以得到虚函数表的地址
5.p[0]=q[0] 改变了Kitty的虚函数表地址,因此在动态绑定中,pa访问的是修改后的虚函数表,为jd的虚函数表,因此调用的是jd::print_age().
6.覆盖掉的是虚表指针,而成员变量没有替换
综上所述:选择B

52.有以下类定义:

#include <iostream>
using namespace std;
class shape 
{public:  
        virtual int area()=0;
};  
class rectangle:public shape 
{public: 
        int a, b;  
        void setLength (int x, int y) {a=x;b=y;} 
        int area() {return a*b;} 
};

若有语句定义rectangle r; r.setLength(3,5); 则编译时无语法错误的语句是( )
A.shape *s1=&r;
B.shape &s2=r;
C.shape s3=r;
D.shape s4[3];

解析:AB
shape为抽象类,不可实例化

53.有如下程序

#include<stdio.h>
int main()
{
    if('\0' == 0)putchar('X');
    if('\0' == 0)putchar('Y');
    if('a' > 'b')putchar('Z');
    printf("\n");
}

程序运行后的输出结果是()

解析:XY 
感觉是在考 "\0" '\0'
'\0' 代表的就是 0 ;
而"\0"代表的是字符串的地址

54.阅读以下代码:

class B
{
public:
   virtual void Fun(){}
};
class D: public B
{
public:
   void Fun(){}
};
D dd;
B* pb = &dd;
D* pd = &dd;
pb->Fun();
pd->Fun();

上述例程调用的Fun函数顺序为()
A.B::Fun, D::Fun
B.B::Fun, B::Fun
C.D::Fun, D::Fun
D.D::Fun, B::Fun

解析:C
本题中,根据兼容性原则:当父类指针(引用)指向子类对象时,子类对象退化成父类对象,只能访问父类中定义的成员
如果B对象没有virtual修饰的话,B* pb = &dd; dd就会退化为父类对象,pd就只能访问父类的成员B::Fun()。
但是又virtual修饰的话,就会展现多态行为,会根据实际指针指向的对象判断函数的调用。pb 和pd都指向子类对象,所以调用D::Fun()

55.函数rewind的作用是()
A.使位置指针重新返回文件的开头
B.将位置指针指向文件中所要求的特定位置
C.使位置指针指向文件的末尾
D.使位置指针自动移至下一个字符位置

解析:A

56.下面C++程序的输出是:

void f(char * x)
{
    x++;
    *x='a';
}
int main()
{
    char str [sizeof("hello")];
    strcpy(str, "hello");
    f(str);
    cout<<str;
    return 0;
}

解析:hallo
str是一个指针,f(str)是地址传递,可以改变地址所指向内容的值,但是地址str本身没有改变,若想要改变地址str的值,需要传二级指针(&str)

57.()是用同一个名字引用的相关变量的集合。
A.结构
B.联合
C.变量
D.枚举

解析:A
枚举是常量;共用体(联合)是一种同一存储区域由不同类型变量共享的数据类型。结构体是用同一个名字引用的相关变量的集合。

58.在C++中,下列哪一个可以做为有继承关系的对象之间安全的转换:

A.static_cast
B.dynamic_cast
C.const_cast
D.reinterpret_cast
解析:转化指的是通过改变一个变量的类型从而改变变量的表示方式。
c++标准定义了四个新的转换符:static_cast dynamic_cast const_cast reinterpret_cast,目的在于控制类(class)之间的类型转换。
对于选项A static_cast可以用于类层次结构中基类和子类之间指针或引用的转换。把子类的指针或引用转换成基类表示是安全的,但把基类的指针或引用转化成子类的指针或引用时,没有动态类型检查,所以它是不安全的。基类和子类之间的动态类型转换一般建议使用dynamic_cast。 static_cast 可以用作对象继承之间转换,只不过有安全隐患,因此A选项不正确。

对于选项B,dynamic_cast用于对象的指针和引用,当用于多态类型转换时,允许隐式转换及相反的转换操作,与static_cast的不同之处在于,在相反的转换过程中,dynamic_cast会检测操作的有效性,如果返回的不是被请求的有效完整对象,则返回null,反之返回一个有效的对象,如果时引用返回无效时,则会抛出bad_cast异常,选项B正确

对于选项C const_cast 用于修改类型的const或volatile属性,具体而言,const_cast会操纵传递对象的const属性,设置或者移除该属性。所以,选项C错误。

对于选项D  reinterpret_cast 用来处理无关类型之间的转换,可以转换任意一个32位整数,包括所有的指针和整数,可以把任何整数转换成指针,也可以把任何指针转换成整数,以及把指针转换位任意类型的指针,但不能将非32位的实例转换成指针。所以,选项D错误。所以本题的答案为B。

在这里插入图片描述
没有重载下列哪个运算符()
A.==
B.++
C.*
D.>>

解析:D 迭代器相当于是c++中的指针进行看待,指针没有进行右移和左移运算。

60.C++类体系中,不能被派生类继承的有()
A.构造函数
B.静态成员函数
C.非静态成员函数
D.赋值操作函数

解析:ABD  缺省构造函数 拷贝构造函数 拷贝赋值函数以及析构函数这四种成员函数被称作特殊的函数,这四种成员函数不被继承。

61.构造异质链表的意义是()?
A.用数组组织类对象
B.用链表组织类对象
C.用抽象类指针指向派生类对象
D.用抽象类指针构造派生类对象链表

解析:D

62.以下代码的输出结果是:

#include <stdio.h>
#define a 10 

void foo();  
int main(){ 
   printf("%d..", a); 
   foo(); 
   printf("%d", a); 
} 
void foo(){ 
   #undef a 
   #define a 50 
}

A.10…10
B.10…50
C.Error
D.0

解析:A define在预处理阶段就把main中的a全部替换成10了,另外,不管是在某个函数内,还是函数外,define都是从定义开始知道文件结尾,所以如果把foo函数放到main上面的话,则结果会是50..50
enum string{    
    x1,    
    x2,    
    x3 = 10,    
    x4,    
    x5,    
} x;

函数外部访问x等于什么?
A.0
B.随机值

解析:A   局部变量初始化是随机值,全局变量初始化为0,

64.以下程序段执行后结果是()

#include<stdio.h>
int main(){
    short *p,*q;
    short arr[15] = {0};
    p = q = arr;
    p++;
    printf("%d,", p - q);
    printf("%d,", (char*)p - (char*)q);
    printf("%d", sizeof(arr) / sizeof(*arr));
}

A. 1 0 15
B.0 2 1
C.1 1 15
D.1 2 15

解析:D 
(1)指针相减的值是指针地址地址的偏移除以指针每次位移的大小,指针p和q都为short类型,偏移两个字节,每次移动两个字节,所以p-q=2/2=1;
(2)(char*)p及(char*)q是将p和q转化为char类型的指针,每次移动一个字节,但是p和q原本是short类型,偏移量为两个字节,所以(char*)p-(char*)q=2/1=2;
(3)sizeof(*arr)表示的是arr数组的第一个字符所占的大小为2个字节,sizeof(arr)表示数组所有元素的字节个数为15*2=30个字节,两者相除代表数组元素个数。

65.下列关于面向对象的说法正确的有()
A.面向对象的最重要的特性是支持继承、封装和多态
B.系统设计应遵循开闭原则,系统应该稳定不可修改,但应支持通过继承、组合等方式进行扩展
C.函数式的语言必然是面向对象的语言
D.面向对象设计时,每个类的职责应该单一,不要再一个类中引入过多的接口
E.过程式语言和面向对象的语言各有其优势,过程式语言更加灵活,面向对象语言更加强调抽象和封装
F.Java和C++都是静态类型的面向对象编程语

解析:ABDEF
C.  c语言是函数式编程语言但是是面向过程的,非面向对象语言

66.以下关于构造函数描述错误的是()
A.每个类有且只能有一个构造函数
B.构造函数是类的一种特殊函数,它的方法名必须与类名相同
C.构造函数的主要作用是完成对类的对象的初始化工作
D.一般在创建新对象时,系统会自动调用构造函数

解析:A
构造函数又叫构造器。如果一个类在没有自定义构造器时,系统会自动匹配一个无参构造器给该类,但一旦你自己定义了一个构造器,那么默认匹配的构造器将失效。构造器定义没有返回值类型,命名必须与类名一致,用于实例化类对象。

67.下列字符串可以用作C++标识符的是:
A._123
B.2009var
C.goto
D.test-2009

解析:A
标识符
标识符用来表示函数、类型及变量的名称,是字母、下划线和数字的排列。
1、必须用字母或下划线开头。
2、只能是字母、下划线、数字的组合,不能出现其他符号。
2、大小写的含义是不同的。
3、标识符的名称不能是C语言中的关键字,关键字是具有特定含义的标识符
union test {
    int x;
    char y;
    float z;
};

在32位平台上,这个联合的大小是()字节
A. 7 B.2 C.1 D.4

解析:D 
32 位机器上int为 4 字节、char 为 1 字节、float 为 4 字节。union 大小为 union 内最大元素的字节数。
#include<iostream>  
using namespace std;  
#include <iomanip> 
int main()
{ 
    int i=7890; 
    cout<<setw(6)<<i<<endl;
    cout<<i<<endl;
}

运行之后会输出()
A. 7890
7890
B. 7890
7890
C.D.

解析:B  setw(int)作用是根据输入的int值,保证输出的位数,默认右对齐(可用setiosflags()修改),并用空格(可用setfill()修改)在左侧填充不足的位数。	

70 . 下列程序的运行结果是B0,横线处缺失的程序代码为()

#include <iostream>

using namespace std;
class B0 {
public:
    virtual void display() {
        cout << "B0" << endl;
    }
};

class B1: public B0 {
public:
    void display() {
        cout << "B1" << endl;
    }
};

class D1: public B1 {
public:
    void display() {
        cout << "D1" << endl;
    }
};

void fun(______) {
    ptr.display();
}

int main() {
    D1 d1;
    fun(d1);
}

A. B0 &ptr
B. D1 &ptr
C. D1 ptr
D. B0 ptr

解析:D
类B0 B1 D1均包含虚函数,传引用和指针依然指向原来的对象d1,因此会触发正常虚函数调用。但是传值会触发拷贝函数,如果参数为B0 ptr,则指向的是B0对象,调用ptr.display();程序输出为B0;

71 . 对下面的程序段

#include<bits/stdc++.h>
using namespace std;
class CA
{
public:
    virtual void f1()
    {
        cout<<"CA::f1( )"<<endl;
        f2();
    }
    void f2()
    {
        cout<<"CA::f2( )"<<endl;
    }
};
class CB : public CA
{
public:
    void f1()
    {
        cout<<"CB::f1( )"<<endl;
        f2();
    }
    void f2()
    {
    cout<<"CB::f2( )"<<endl;
    }
};
class CC:public CB
{
public:
    virtual void f2()
    {
        cout<<"CC:f2()"<<endl;
    }
};
int main()
{
    CC c;
    CA *pA = &c ;
    pA->f1();
    return 0;
}

编译运行后,程序输出结果是()
A. CB::f1() CC::f2()
B. CB::f1() CB::f2()
C. CB::f1() CA::f2()
D. CA::f1() CC::f2()

解析:
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值