c++基础知识积累

来源:互联网 发布:软件开发心得体会 编辑:程序博客网 时间:2024/05/21 13:59
20161017
1.当一个类A 中没有声明任何成员变量与成员函数,这时sizeof(A)的值是多少?
1
0
4
运行时错误
百度:class CBase{};运行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;sizeof(CBase)=1;深度探索c++对象模型中是这样说的:     那是被编译器插进去的一个char ,使得这个class的不同实体(object)在内存中配置独一无二的地址。     也就是说这个char是用来标识类的不同对象的。

2指出下面程序哪里可能有问题?
class CBuffer{    char * m_pBuffer;    int m_size;    public:        CBuffer()        {            m_pBuffer=NULL;        }        ~CBuffer()        {            Free();        }        void Allocte(int size) (1) {            m_size=size;            m_pBuffer= new char[size];    }    private:        void Free()        {            if(m_pBuffer!=NULL) (2)            {                delete[] m_pBuffer;                m_pBuffer=NULL;            }        }    public:        void SaveString(const char* pText) const (3)        {            strcpy(m_pBuffer, pText); (4)        }        char* GetBuffer() const        {            return m_pBuffer;     }     }; void main (int argc, char* argv[]){    CBuffer buffer1;    buffer1.SaveString("Microsoft");    printf(buffer1.GetBuffer());}




1
2
3
4


正确答案应该为: A C D
理由: (1) 分配内存时, 未检测m_pBuffer是否为空, 容易造成内存泄露;
         (3) 常成员函数不应该对数据成员做出修改, 虽然可以修改指针数据成员指向的数据, 但原则上不应该这么做;
         (4) 字符串拷贝时, 未检测是否有足够空间, 可能造成程序崩溃。

以下程序的运行结果是:
1
2
3
4
5
intmain(void){
 intm=5;
 if(m++>5)cout<<m<<endl;
 elsecout<<--m;
}

正确答案: B   你的答案: A (错误)

4
5
7
6
m=5,if(m++)>5判断时,++在判断后执行,因此判断为false,之后m自增为6;然后执行cout << --m,自减操作在输出前执行,因此输出5.

类B从类A派生,则类B可以访问类A中的( )成员?

正确答案: A C   你的答案: C D E (错误)

public成员
private成员
protected成员
数据成员
函数成员



x为整型,请用位运算实现x%8 1 。

你的答案 (错误)

1 x&8
参考答案 x&7
x为整型,请用位运算实现x%8 1 。

你的答案 (错误)

1 x&8
参考答案 x&7

请阅读下面代码片段并且回答问题:
1
2
3
4
5
6
7
8
9
10
11
12
#define SIZE_20M (20*1024*1024)
voidfunc_a()
{
    char*temp = malloc(SIZE_20M)
    return;
}
voidfunc_b()
{
    chartemp[SIZE_20M];
    //...do something using temp
    return;
}

关于这段代码,下列说法正确的是

正确答案: B   你的答案: D (错误)

func_a 获得临时内存的方式效率通常更高。
func_b 使用了太多的栈,程序可能会在运行时候崩溃。
func_b 存在内存泄露
func_a 和func_b 分配的内存会自动初始化0

//A.栈区效率比堆区高,malloc分配的空间在堆区,临时变量分配在栈区。

区别是:栈区由电脑自己清除(用完自动删),堆区需要程序员清除,或者程序结束后由系统清除

 B.栈一般能放2M大小

 C.func_a会发生内存泄漏(使用动态内存分配,使用完未删除就会造成泄漏。或者是如果没有任何一个指针指向那块动态内存,那它就泄漏了)

 D.堆区和栈区都不会自动初始化,自动初始化会在未赋值的静态/全局区。

void * malloc(usingned int size);单位是(byte)字节数   其作用是在内容的动态存储区分配一个长度位 side 空间,此函数是一个指针型函数,返回的指针是该分配区域的开头的位置(或首地址) 注意指针的类型位void 即不指向任何类型的数据,只提供一个地址。放什么类型的数据,强制转换为什么类型。 如果函数未能成功申请到空间(内存不足),返回空指针 NULL
上面的代码也该改为
1
char*temp = (char*)malloc(SIZE_20M);

x为整型,请用位运算实现x%8 1 。

你的答案 (错误)

1 x&8
参考答案 x&7
声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()

正确答案: C   你的答案: C (正确)

(int *p[10])(int*)
int [10]*p(int *)
int (*(*p)[10])(int *)
int ((int *)[10])*p
以上选项都不正确
 
首先题目说要声明一个数组指针,  一般我们想到的数组指针是 随便来一个 int(*p)[10],    然后又说每个元素是一个函数指针,那么我们随便来一个 函数指针  int (*pf)(int *) . 然后把(*p)[10]作为一个整体替代 pf     即   int(*(*p)[10]))(int *);    分析: 判断一个复杂式子看最高优先级的,*p是一个指针,然后(*p)外面是[],所以是数组指针,(*p)[10])描述完毕,然后再看外面int(*)(int *)很明显,这是一个函数指针,所以这个数组中每个元素是函数指针

如下程序:
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
#include "stdio.h"
classBase
{
public:
    Base()
    {
        Init();
    }
    virtualvoid Init()
    {
        printf("Base Init\n");
    }
    voidfunc()
    {
        printf("Base func\n");
    }
};
classDerived: publicBase
{
public:
    virtualvoid Init()
    {
        printf("Derived Init\n");
    }
    voidfunc()
    {
        printf("Derived func\n");
    }
};
 
intmain()
{
    Derived d;
    ((Base *)&d)->func();
     
    return0;
}
该程序的执行结果
  • Base InitDerived func
  • Base InitBase func
  • Derived InitBase func
  • Derived InitDerived func
    查看正确选项
    • 添加笔记
    • 求解答(4)
    • 邀请回答
    • 收藏
    • 纠错

    8个回答

     添加回答
    • flywith
      在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
      在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
      发表于 2015-07-18 21:45:30回复(1)
      • baomizhu:
        写的好
        2015-08-31 11:26:33回复赞(0)
      回复
    • Aesthetic92
      Derived d;首先创建对象d,找到基类的构造函数Base(){Init();},此时需要调用Init()函数,不要被virtual迷惑,这只是普通的调用函数,虚函数不起作用,所以调用的还是基类的Init(),输出Base Init;
      ((Base *)&d)->func(),虽然是动态联编,但是func()不是虚函数,Base*指针指向派生类不起作用,执行的是基类的func(),输出Base func;

      故选 B
      编辑于 2015-10-05 21:59:05回复(3)
    • 吴桐
      当派生类对象生成的时候会调用构造函数,首先调用基类的构造函数生成基类部分,然后调用自己的构造函数,析构的时候顺序正好相反,先析构自身的然后析构释放派生类的
      发表于 2015-05-04 09:38:35回复(0)
    • 风拔萝卜
      要明确一点,在构造函数执行完以后虚函数表才能正确初始化,所以在构造函数中调用虚函数时此时虚函数表还没有被正确初始化,调用的是本类的函数,即静态类型所对应的函数,同理在析构函数中也不能调用虚函数,因为此时虚函数表已经被销毁
      发表于 2016-09-11 12:21:22回复(0)
    • 你耀世璀璨
       ((Base *)&d)->func();,这个不懂,求大神解释.这个按我的理解不就是d->func(),前面的(base*)
      无效,d是派生类对象的,那调用的不就是派生类的函数么。
      发表于 2016-09-13 22:46:14回复(0)
    • 哦吼嘿呦
      1.创建派生类对象时,程序首先创建基类对象。基类对象应当在程序进入派生类构造函数之前被创建。
      2. 虚方法:如果没有使用关键字virtual,程序将根据引用类型或者指针类型来选择方法;如果使用了virtual,程序将根据引用或者指针指向的对象的类型来选择方法。
      发表于 2016-07-25 10:37:03回复(0)
    • BryanSun
      可以看一下
      Effective c++的条款9
      发表于 2016-07-05 15:08:38回复(0)
    • 荔枝味儿
      1. 子类Derived中并没有定义构造函数,因此在执行Derived d语句的时候会掉用基类中的构造函数,因此输出 Base Init
      2.基类中的voidfunc()函数并没有定义成 virtual voidfunc() = 0;的形式,因此,((Base *)&d)即基类对象的指针所调用的func为基类中的func






    0 0