C++学习(32)

来源:互联网 发布:类似日事清的软件 编辑:程序博客网 时间:2024/05/17 23:30

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。

 

原创粉丝点击