【原文链接】

http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-1-10.html

题目1

我们可以用static修饰一个类的成员函数,也可以用const修饰类的成员函数(写在函数的最后表示不能修改成员变量,不是指写在前面表示返回值为常量)。请问:能不能同时用static和const修饰类的成员函数?

分析

不可以。C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。我们也可以这样理解:两者的语意是矛盾的。static是针对类型,与类的实例没有关系;而const是针对实例,确保函数不能修改实例的状态。因此不能同时用它们。


题目2

运行下面的代码,输出是什么?

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
class A
{
};

class B
{
public:
    B() {}
    ~B() {}
};

class C
{
public:
    C() {}
    virtual ~C() {}
};

int _tmain(int argc, _TCHAR *argv[])
{
    printf("%d, %d, %d\n", sizeof(A), sizeof(B), sizeof(C));
    ;
}

分析

答案是1, 1, 4。

class A是一个空类型,它的实例不包含任何信息,本来求sizeof应该是0。但当我们声明该类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。至于占用多少内存,由编译器决定。Visual Studio 2008中每个空类型的实例占用一个byte的空间。

class B在class A的基础上添加了构造函数和析构函数。由于构造函数和析构函数的调用与类型的实例无关(调用它们只需要知道函数地址即可),在它的实例中不需要增加任何信息。所以sizeof(B)和sizeof(A)一样,在Visual Studio 2008中都是1。

class C在class B的基础上把析构函数标注为虚拟函数。C++的编译器一旦发现一个类型中有虚拟函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针。在32位的机器上,一个指针占4个字节的空间,因此sizeof(C)是4。


题目3

运行下面中的代码,得到的结果是什么?

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
#include "stdafx.h"

class A
{
private:
    int m_value;

public:
    A(int value)
    {
        m_value = value;
    }
    void Print1()
    {
        printf("hello world");
    }
    void Print2()
    {
        printf("%d", m_value);
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = NULL;
    pA->Print1(); // "hello world"
    pA->Print2(); // ERROR

;
}

分析

答案是Print1调用正常,打印出hello world,但运行至Print2时,程序崩溃。调用Print1时,并不需要pA的地址,因为Print1的函数地址是固定的。编译器会给Print1传入一个this指针,该指针为NULL,但在Print1中该this指针并没有用到。只要程序运行时没有访问不该访问的内存就不会出错,因此运行正常。在运行print2时,需要this指针才能得到m_value的值。由于此时this指针为NULL,因此程序崩溃了。


题目4

运行下面中的代码,得到的结果是什么?

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
class A
{
private:
    int m_value;

public:
    A(int value)
    {
        m_value = value;
    }
    void Print1()
    {
        printf("hello world");
    }
    virtual void Print2()
    {
        printf("hello world");
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = NULL;
    pA->Print1();
    pA->Print2();

;
}

【分析】

答案是Print1调用正常,打印出hello world,但运行至Print2时,程序崩溃。Print1的调用情况和上面的题目一样,不在赘述。由于Print2是虚函数。C++调用虚函数的时候,要根据实例(即this指针指向的实例)中虚函数表指针得到虚函数表,再从虚函数表中找到函数的地址。由于这一步需要访问实例的地址(即this指针),而此时this指针为空指针,因此导致内存访问出错。


题目5

静态成员函数能不能同时也是虚函数?

【分析】

答案是不能。调用静态成员函数不要实例,但调用虚函数需要从一个实例中获取指向虚函数表的指针以得到函数的地址,因此调用虚函数需要一个实例。两者相互矛盾。


题目6

运行下列C++代码,输出什么?

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
#include "stdafx.h"

struct Point3D
{
    int x;
    int y;
    int z;
};

int _tmain(int argc, _TCHAR *argv[])
{
    Point3D *pPoint = NULL;
    int offset = (int)(&pPoint->z);

printf("%d", offset); // 8
;
}
/*
+       pPoint  0x00000000 {x=??? y=??? z=??? } Point3D *
+       &pPoint->x  0x00000000  int *
+       &pPoint->y  0x00000004  int *
+       &pPoint->z  0x00000008  int *
*/

【分析】

输出8。&(pPoint->z)的语意是求pPoint中变量z的地址(pPoint的地址0加z的偏移量8),并不需要访问pPoint指向的内存。只要不访问非法的内存,程序就不会出错。


题目7

运行下列C++代码,输出什么?

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 
#include "stdafx.h"

class A
{
public:
    A()
    {
        Print();
    }
    ~A()
    {
        printf("A is erased.\n");
    }
    virtual void Print()
    {
        printf("A is constructed.\n");
    }
};

class B: public A
{
public:
    B()
    {
        Print();
    }
    ~B()
    {
        printf("B is erased.\n");
    }
    virtual void Print()
    {
        printf("B is constructed.\n");
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = new B();
    delete pA;

B *pB = new B();
    delete pB;

;
}
/*
A is constructed.
B is constructed.
A is erased.

A is constructed.
B is constructed.
B is erased.
A is erased.
*/

【分析】

输出结果如上所示。


【题目8】

运行下列C#代码,输出是什么?

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
namespace ChangesOnString
{
    class Program
    {
        static void Main(string[] args)
        {
            String str = "hello";
            str.ToUpper();
            str.Insert(, " WORLD");

Console.WriteLine(str);
        }
    }
}

【分析】

输出是hello。由于在.NET中,String有一个非常特殊的性质:String的实例的状态不能被改变。如果String的成员函数会修改实例的状态,将会返回一个新的String实例。改动只会出现在返回值中,而不会修改原来的实例。所以本题中输出仍然是原来的字符串值hello。如果试图改变String的内容,改变之后的值可以通过返回值拿到。用StringBuilder是更好的选择,特别是要连续多次修改的时候。如果用String连续多次修改,每一次修改都会产生一个临时对象,开销太大。


【题目9】

在C++和C#中,struct和class有什么不同?

【分析】

在C++中,如果没有标明函数或者变量是的访问权限级别,在struct中,是public的;而在class中,是private的。

在C#中,如果没有标明函数或者变量的访问权限级别,struct和class中都是private的。

struct和class的区别是:struct定义值类型,其实例在栈上分配内存;class定义引用类型,其实例在堆上分配内存。


【题目10】

运行下图中的C#代码,输出是什么?

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
namespace StaticConstructor
{
    class A
    {
        public A(string text)
        {
            Console.WriteLine(text);
        }
    }

class B
    {
        static A a1 = new A("a1");
        A a2 = new A("a2");

static B()
        {
            a1 = new A("a3");
        }

public B()
        {
            a2 = new A("a4");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
        }
    }
}

【分析】

打印出四行,分别是a1、a3、a2、a4。

在调用类型B的代码之前先执行B的静态构造函数。静态函数先初始化类型的静态变量,再执行静态函数内的语句。因此先打印a1再打印a3。接下来执行B b = new B(),即调用B的普通构造函数。构造函数先初始化成员变量,在执行函数体内的语句,因此先后打印出a2、a4。

【参考】

http://zhedahht.blog.163.com/blog/static/254111742011012111557832/

【原文链接】

http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-1-10.html

C++基础知识面试精选100题系列(1-10题)[C++ basics]的更多相关文章

  1. C++基础知识面试精选100题系列(11-20题)[C++ basics]

    [原文链接] http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-11-20.html [题 ...

  2. C++基础知识面试精选100题系列(21-30)[C++ basics]

    [本文链接] http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-21-30.html [题 ...

  3. C#基础知识面试经典[整理]

    个人网站:http://www.51pansou.com .net视频下载:.net视频教程 .net源码下载:.net源码 当初学 C# 时是找个人大概问了一下数据类型和分支语句就开始做项目了.这两 ...

  4. Leetcode第1题至第10题 思路分析及C++实现

    笔者按照目录刷题,对于每一道题,力争使用效率最高(时间复杂度最低)的算法,并全部通过C++代码实现AC.(文中计算的复杂度都是最坏情况复杂度) 因为考虑到大部分读者已经在Leetcode浏览过题目了, ...

  5. .Net及C#基础知识,面试宝典

    作为你一.Net和C#开发这些知识,你是否掌握了,你是否算的上一名入门的程序员? 技术不行并不可怕,可怕的是你不知道自己还需做哪一方面的提升,本篇文字本人的一些面试时所经常涉及的问题,并且在网上收集了 ...

  6. java基础知识面试总结-部分

    前言 在平时的工作学习中,自己对微服务和springboot基础理论知识关注比较少,在面试中对于面试官的问题,很多基本都不能够达到精准,全面:现将自己面试中的问题做以总结: 1.谈谈你对微服务架构的认 ...

  7. BAT机器学习面试1000题系列(41-45题)

    41.线性分类器与非线性分类器的区别以及优劣 如果模型是参数的线性函数,并且存在线性分类面,那么就是线性分类器,否则不是.常见的线性分类器有:LR,贝叶斯分类,单层感知机.线性回归常见的非线性分类器: ...

  8. MySQL基础知识面试与答案

    1.Mysql 的存储引擎,myisam和innodb的区别. 答: 1.MyISAM 是非事务的存储引擎,适合用于频繁查询的应用.表锁,不会出现死锁,适合小数据,小并发. 2.innodb是支持事务 ...

  9. 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数

    1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...

随机推荐

  1. Java-transient

    transient的作用及使用方法 都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这 ...

  2. 本地的手机号码归属地查询-oracle数据

    最近做的项目中,有个功能是手机归属地查询,因为项目要在内网下运行,所以不能用提供的webservice,只好在网上找手机归属地的数据,很多都是access的,我们的项目是用oracle,只好自己转吧, ...

  3. 【CodeForces 621B】Wet Shark and Bishops

    题 题意 1000*1000的格子里,给你n≤200 000个点的坐标,求有多少对在一个对角线上. 分析 如果求每个点有几个共对角线的点,会超时. 考虑到对角线总共就主对角线1999条+副对角线199 ...

  4. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  5. codevs1746 贪吃的九头龙

    [问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...

  6. Visio绘制时序图

    用visio建立时序图 1.选择模版 2.常见符号 时序图创建步骤 1.确定交互过程的上下文: 2.识别参与过程的交互对象: 3.为每个对象设置生命线: 4.从初始消息开始,依次画出随后消息: 5.考 ...

  7. CodeReview Learning

    目录 . 引言 . 代码检视的指导思想 . 代码检视的内容 . 回归测试 0. 引言 代码检视(Code Review)是指软件开发人员在完成代码设计.编写.调试后展开的个人或群体性的代码阅读过程,代 ...

  8. 牛顿迭代法求n方根

    一.简单推导 二.使用 借助上述公式,理论上可以求任意次方根,假设要求a(假设非负)的n次方根,则有xn=a,令f(x)=xn-a,则只需求f(x)=0时x的值即可.由上述简单推导知,当f(x)=0时 ...

  9. Java及Android开发环境搭建

    前言 自从接触java以来,配置环境变量折腾了好几次,也几次被搞得晕头转向,后来常常是上网查阅相关资料才解决.但是过一段时间后一些细节就会记不清了,当要在其他机子上配置时又得上网查或者查阅相关书籍,如 ...

  10. centos 搭建gitlab

    #修改yum源 yum -y install wget cd /etc/yum.repos.d wget -O CentOS-Base.repo http://mirrors.aliyun.com/r ...