1. 

#include<iostream>
#include<string.h>
using namespacestd;
struct A{
      int a;
      char b;
};
 
class B{
};
class C{
      char b[0];
};
int main() {
 
      cout<<sizeof(A)<<""<<sizeof(B)<<" "<<sizeof(C)<<endl;
      return 0;
}

分析:类的实例化是在内存中分配一块地址,每个实例在内存中都有独一无二的二地址。同样,空类也会实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化后就有独一无二的地址了。所以,空类的sizeof为1,而不是0. 多重继承的空类的大小也是1.

 

2.

#include<iostream>
#include<string.h>
using namespace std;
class A{
    public:
    int_a;
    A(){
       _a=1;
    }
    voidprint() {
       cout<<_a;
    }
};
 
class B:public A{
    public:
       int_a;
       B(){
           _a=2;
       }
};
class C{
    charb[0];
};
int main() {
    Bb;
    b.print();
    cout<<b._a;
    return0;
}

分析:因为在继承的时候,允许子类存在与父类同名的成员变量,子类会屏蔽父类的成员变量,他们同时存在。 因为给孩子类中没有定义print函数,所以会按照就近原则去寻找父类中是否有print函数。恰好父类中有这个函数,于是调用父类的print函数。所以b.print()这个函数会调用父类的a变量。


子类公有(public)继承父类,所以子类可以通过对象访问父类的公有成员函数,由于调用的是父类的公有成员函数(该函数中的this指针存放的是父类对象的地址),所以打印的是父类A的_a。


3、
C++真正正式公布的标准就三个:C++98、C++03、C++11。
其中C++98是第一个正式C++标准,C++03是在C++98上面进行了小幅度的修订,C++11则是一次全面的大进化(C++0x是C++11标准成为正式标准之前的草案临时名字)。

 

class foo() {
foo(){};
};
class boo:public foo {
boo():foo(){};
};

A c++03    B c++0x    C c++11       D c++98    E 都不正确

分析:委托构造是对同一类而言,参数类型不同的构造函数可以调用自己的其他构造函数,这个地方就是派生类调用基类的构造,所以并不是委托构造。但是,这个题出了点小插曲,就是foo()在foo类里默认是private的,所以编译时不通过,可能是题目的疏忽。


委托构造函数同一个类的一个构造函数调用另一个构造函数。这道题应该选E,因为根本编译不通过。父类的private构造函数子类无法通过任何方式访问到。


4. Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions)。系统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思,面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的api。

简明的回答是:函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一部分。

 

Pwrite是系统调用,而其他的库函数。

 

fcntl 文件控制

open 打开文件

creat 创建新文件

close 关闭文件描述字

read 读文件

write 写文件

readv 从文件读入数据到缓冲数组中

writev 将缓冲数组里的数据写入文件

pread 对文件随机读

pwrite 对文件随机写

lseek 移动文件指针

_llseek 在64位地址空间里移动文件指针

dup 复制已打开的文件描述字

dup2 按指定条件复制文件描述字

flock 文件加/解锁

poll I/O多路转换

truncate 截断文件

ftruncate 参见truncate

umask 设置文件权限掩码

fsync 把文件在内存中的部分写回磁盘

 

5.

#include<iostream>
#include<string.h>
using namespace std;
int main() {
    staticchar*s[]={"black","white","pink","violet"};
    char**ptr[]={s+3,s+2,s+1,s},***p;
    p=ptr;
    ++p;
    printf("%s",**p+1);
    return0;
}



6.

#include<iostream>
#include<string.h>
using namespace std;
class B0{
    public:
       virtualvoid display() {
           cout<<"B0::display"<<endl;
       }
};
class B1:public B0{
    public:
       voiddisplay() {
           cout<<"B1::display0"<<endl;
       }
};
class D1:public B1 {
    public:
       voiddisplay() {
           cout<<"D1::display0"<<endl;
       }
};
 
void fun(B0 ptr) {
    ptr.display();
}
int main() {
    B0b0;
    B1b1;
    D1d1;
    fun(b0);
    fun(b1);
    fun(d1);
    return0;
}

分析:此题的关键点在于fun函数,传入的参数是一个类的对象,这样,派生类作为参数传入的时候,会把自动的类型转换为基类对象,这样,display就只是执行基类的函数了。选B0::display() B0::display() B0::display()

void fun(B0 ptr) {   ptr.display();}//这里使用的不是按地址传递,程序在这里转化为基类对象,直接调用基类的成员函数。如果是指针传递,改变为B0*ptr,ptr->display(),可以实现多态。

改完后的程序为:

#include<iostream>
#include<string.h>
using namespace std;
class B0{
    public:
       virtualvoid display() {
           cout<<"B0::display"<<endl;
       }
};
class B1:public B0{
    public:
       voiddisplay() {
           cout<<"B1::display0"<<endl;
       }
};
class D1:public B1 {
    public:
       voiddisplay() {
           cout<<"D1::display0"<<endl;
       }
};
 
void fun(B0 *ptr) {
    ptr->display();
}
int main() {
    B0*b0=new B0;
    B1*b1=new B1;
    D1*d1=new D1;
    fun(b0);
    fun(b1);
    fun(d1);
    return0;
}


fun(B0 *ptr):使用指针传入结合virtual虚函数,相当于在ptr指针指向的内存空间里边为子类虚函数的实现预留了接口,这样如果传入的是子类,则编译的时候系统会根据子类类别动态加载子类函数;而如果形参不是指针,在编译的时候就不会给子类的虚函数实现留接口,也就无从动态加载子类函数了。另外,如果基函数没有设置函数为virtual类型,同样也不会留接口,不会加载子类函数。

 

在c++中的继承中,如果基类声明了一个函数为虚函数,那么在派生类中不用声明同名函数为虚函数(不需要加virtual)也可以实现该函数为虚函数。虚函数的动态绑定仅在基类指针或引用绑定派生类对象时发生,fun的形参不是指针,所以调用哪个版本的函数编译时就已经确定,根据形参静态类型确定调用B0的成员。

 

应通过指针或引用调用虚函数,而不要用对象名调用虚函数。以派生类对象b1赋值给基类对象b0,并调用Display函数,虽然可以编译通过,但Display()函数却是基类B0的函数。C++中一定要用指针或引用来调用虚函数,才能保证多态性的成立。

 

7.输出数据为:80 8

#include<iostream>
#include<string.h>
using namespace std;
int main() {
    char*p[10],(*p1)[10];//p是一个指针数组,p1是一个指向“包含10个char变量的数组”的数组指针
 
    cout<<sizeof(p)<<""<<sizeof(p1)<<endl;
    return0;
}


分析:重点理解p跟谁结合了,跟[]结合,则p就是一个数组;跟*结合,p就是一个指针;

首先[]()的优先级一样,均大于* char *p[10],p与[]结合,所以p就是一个数组,数组的元素比较特殊,是指针,指针大小为8,所以是10*8=80;

char(*p1)[10],与*结合,所以是一个指针,大小为8;

 

补充:什么是数组名降级?数组退化?
数组名降级和数组退化是一个概念,它是在某些情况下,对数组的引用会退化为指针。点击打开链接


8.

#include<iostream>
#include<string.h>
using namespace std;
int i=1;
class MyCls{
  public:
    MyCls():m_nFor(m_nThd),m_nSec(i++),m_nFir(i++),m_nThd(i++){
       m_nThd=i;
     }
     void echo() {
       cout<<"result:"<<m_nFir+m_nSec+m_nThd+m_nFor<<endl;
     }
  private:
     int m_nFir;
     int m_nSec;
     int m_nThd;
     int &m_nFor;
};
int main() {
  MyCls oCls;
    oCls.echo();
  return 0;
}


分析:构造函数中变量的初始化顺序是按其定义的顺序,与初始化列表无关、

首先要明白变量初始化的顺序是其声明的顺序,跟初始化列表中的顺序无关。所以变量的初始化顺序为m_nFir(i++),m_nSec(i++),m_nThd(i++),&m_nFor(m_nThd);
i初始值为1,所以经过初始化列表初始化以后m_nFir=1,m_nSec=2,m_nThd=3,m_nFor为m_nThd的一个引用。
并且此时i的值为4,构造函数中执行语句m_nThd=i后,m_nThd=4,m_nFor是它的一个引用,自然值也为4。
输出结果m_nFir+m_nSec+m_nThd+m_nFor=1+2+4+4=11。