总结知识点(未完结)

知识点一、C语言与C++的区别是什么?

1)C语言是面向过程,以事件为中心,采用自顶向下顺序执行,逐步求精。程序结构可划分为若干个功能模块,模块内部一般由顺序、选择和循环三种基本结构组成。模块形成树状结构,功能相对独立。利用子函数实现模块,而程序流程在写程序时就已经决定。举例子,五子棋。

2)C++语言是面向对象,把数据及对数据的操作方法放在一起,作为一个整体对象。对同类对象抽象出其共性,即类。类中的大多数数据,只能被本类的方法进行处理。类通过一个简单的外部接口与外界发生关系。程序流程由用户在使用中决定。举例子,人。

3)面向对象用符合常规思维方式,处理客观世界的问题,强调把问题的要领直接映射到对象及对象之间的接口上。面向过程强调过程的抽象化与模块化,以时间为中心构造处理客观问题。

4)面向对象方法是用计算机逻辑来模拟客观实践中的物理存在,以对象的集合类作为处理问题的基本单元,用类的层次结构来体现类之间的继承和发展。面向过程处理问题的基本单位是模块,用模块的层次结构概括模块与模块间的关系和功能

5C++的基本特征有三个:封装,继承和多态。

1)封装:本质上是对客观事物的抽象。将客观事物抽象成类,采用类来描述客观事物的过程,实现了接口和实现的分离。

2)继承:是一个从一般到特殊的过程。可以使用现有类的所有功能,而不需要重新编写原来的类。目的是为了进行代码复用和支持多态。通过继承创建的新类成为派生类,被继承的类成为基类。

3)多态:简单概括就是“一个接口,多种方法”。从实现的角度来讲,多态可以分为两类:编译时的多态性和运行时的多态性。前者是通过静态联编来实现的,比如C++中通过函数的重载和运算符的重载。后者则是通过动态联编来实现的,在C++中运行时的多态性主要是通过虚函数来实现的。可以将父对象设置成为和一个或更多个子对象相等的技术赋值后,父对象可以根据当前赋值给它的子对象的特性以不同方式运行。简单来说,就是允许将基类指针或引用类型绑定到子类对象(称作派生类到基类的隐式转换,基类到派生类不存在隐式转换)。

知识点二、大端存储与小端存储

嵌入式系统开发者应该对Little-endianBig-endian模式非常了解。

采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。

例如,16bit宽的数0x1234Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

4)内存地址

5)0x4000

6)0x4001

7)存放内容

8)0x34

9)0x12

而在Big-endian模式CPU内存中的存放方式则为:

10)内存地址

11)0x4000

12)0x4001

13)存放内容

14)0x12

15)0x34

32bit宽的数0x12345678Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

16)内存地址

17)0x4000

18)0x4001

19)0x4002

20)0x4003

21)存放内容

22)0x78

23)0x56

24)0x34

25)0x12

 

 

而在Big-endian模式CPU内存中的存放方式则为:

26)内存地址

27)0x4000

28)0x4001

29)0x4002

30)0x4003

31)存放内容

32)0x12

33)0x34

34)0x56

35)0x78

请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1

解答:

int checkCPU( )

{

    {

           union w

           { 

                  int a;

                  char b;

           } c;

           c.a = 1;

           return(c.b ==1);

    }

}

 

联合体union的存放顺序是所有成员都从低地址开始存放,面试者的解答利用该特性,轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。如果谁能当场给出这个解答,那简直就是一个天才的程序员。

 

知识点三、下列类声明正确吗?

class A   {  const int size=0;  }

解析:类中的常量有两种实现方式:1)在构造函数的初始化列表中初始化变量;2)将常量设置成static类型。

class A   {  A() {  const int size=0;  }  }

或者class A {  static const int size =0;  }

 

知识点四、编写类string的构造函数、析构函数和赋值函数。

string的原型:

class string

{

public:

    string(const char *str=NULL);//普通构造函数

    string(const string &other);//拷贝构造函数

    

    string& operator=(const string &other);//拷贝赋值函数

    ~string(void);//析构函数

private:

    char *m_data;//用于保存字符串

};

 


 

 

1)构造函数

   实现功能,根据一个字符串常量创建一个MyString对象。构造函数中,首先分配了足量的内存,然后将这个字符串常量复制到这个内存中。

//string类的构造函数

string::string(const char *str)

{

   if(str==NULL)

   {

        m_data=new char[1];

        *m_data='\0';

   }

   else

   {

       int n=strlen(str);//计算输入字符串的长度

       m_data=new char[n+1];//申请内存大小

       strcpy(m_data,str);

   }

}

2)拷贝构造函数

   拷贝构造函数可以在函数调用中以传值方式传递一个MyString参数;还可以在函数以值形式,返回MyString对象时,实现“返回值赋值”

//string类的拷贝构造函数

string::string(const string &other)

{

    int n=strlen(other.m_data);

    m_data=new char[n+1];

    strcpy(m_data,other.m_data);

}

 

3)拷贝赋值函数

拷贝赋值函数可实现字符串的传值活动

//string类的拷贝赋值函数

string& string::operator=(const string &other)

{

  //检查自赋值

  if(this==&other)

        return *this;

  //释放原有资源

  delete [] m_data;

   m_data=NULL;

  

  //分配新的内存资源,并复制内容

  int n=strlen(other.m_data);

  m_data=new char[n+1];

  strcpy(m_data,other.m_data);

  //返回本对象的引用

  return *this;

}

4)析构函数

   为了防止内存泄漏,还需要定义一个析构函数。当一个对象超出它的作用域时,由析构函数释放它所占用的内存。

//string类的析构函数

string::~string(void)

{

    delete [] m_data;

}


 

 

 

 

 

 

 

 

 

 

 

 

知识点十六、拷贝赋值函数和拷贝构造函数

1拷贝赋值函数:将一个类对象赋予给同一类型的对象时,应该做什么。

   实质是,重载了赋值运算符,如果没有定义拷贝赋值函数,则编译器会自动合成一个。

   返回值类型:返回一个该类型的引用,并在函数结束前,返回自身的引用(即*this)。只有返回一个引用,才允许连续赋值。

   函数名关键字operator=

   传入参数:传入类型声明为常量引用,否则,将函数形参复制到实参会调用一次赋值构造函数,引起不必要的消耗。

注意:1要释放实例自身已有的内存分配新内存前,必须先释放自身已有内存,否则,会引起内存泄漏。

2判断传入参数和当前实例(*this)是不是同一个实例如果是,则直接返回当前实例即可。

教材给的解法见上题,考虑异常安全性的解法。常规解法,当检测到传入参数与当前实例不一致时,首先释放了实例m_data的内存。下一步,重新申请内存时,若出现内存不足,则会导致抛出异常,m_data将成为一个空指针,这样容易导致程序崩溃。

也就是说,在拷贝赋值函数中抛出异常,CMyString的实例不再保持有效状态,违背了异常安全性原则。

如下所示:首先创建一个临时实例,再交换临时实例和原来的实例。

CMyString& operator=(const CMyString &str)

{

  if(this!=&str.m_data)

  {

CMyString strtemp(str);   //直接初始化strtemp

     //程序运行到if语句后,局部变量strtemp会自动调用析构函数

char *temp=strtemp.m_data;

strtemp.m_data=m_data;

m_data=temp;

  }

  return *this;

}

2、拷贝构造函数:用同类型的一个对象,初始化本对象时做什么。

   本质还是构造函数,如果没有定义拷贝赋值函数,则编译器会自动合成一个。

   无返回类型,函数名与类同名,传入参数:必须是同类型的常量引用。

原因:若拷贝构造函数传入参数是一个类的实例,即传值参数。此时把形参复制到实参,需要调用拷贝构造函数。因此,如果允许拷贝构造函数进行值传递,就会在拷贝构造函数中调用拷贝构造函数,就会形成无休止的递归调用从而引起栈溢出。因此不允许传值参数。

 

 

 

 

 

注意:1)引用类型和const类型必须初始化。

2)已知fun(int)是类Test的公有成员函数,p是指向成员函数fun()的指针,采用( )是正确的。p=&Test::fun

3常见的文件系统,系统函数:

1. fcntil 文件控制

2. open 打开文件

3. creat 创建新文件

4. close 关闭文件描述字

5. read 读文件

6. write 写文件

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

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

9. pread 对文件随机读

10.pwrite 对文件随机写

知识点五、复制构造函数与赋值运算符的区别

复制构造函数总的来说是构造函数,用于完成基于同一类的其他对象的构建及初始化

特点:1)函数名与类名相同,且无返回类型;

2)只有一个参数,并且为自身类型的引用;

3)每个类必须有一个复制构造函数,若未显示定义,则编译器生成一个合成构造函数;

4)目的是新建一个对象实例。保证新建对象有独立内存空间,不能与先前对象共用内存。

赋值操作符,用于用已存在的对象来创建另一个对象,且给对象赋予新值

复制构造函数与赋值运算符的不同如下:

1)复制构造函数生成新的类对象,而复制运算符则不能。

2)前者用于生成新类型,所以初始化对象之前不用检测源对象是否和新建对象相同;

   而后者需要,且如果原对象中有内存分配,要先把内存释放掉。

3)当类中有指针类型的成员变量时,一定要重写复制构造函数和赋值构造函数,不能使用默认。

知识点六、overload(重载)override(覆盖)的区别

Overload(重载),是指编写一个函数与已有函数的函数名相同,但是参数列表不同。

参数列表不同,指参数类型、个数和顺序,至少一项不同;对于重载函数的调用,在编译期间就已经确定,是静态的;例如一个函数既可以接收整型数作为参数,也可以接收浮点型数作为参数。注意:重载不关心返回值类型!!!

Override(覆盖),是指派生类重写基类的虚函数,重写的函数必须有一致的返回值类型、函数名和参数表;覆盖发生在函数的运行阶段

知识点七、C++中继承的成员变量的覆盖/重写

首先需要明白:

1)成员函数的覆盖,是指子类对父类虚函数的覆盖,必须要求函数返回类型、函数名和参数列表同时一致。

2)成员变量的覆盖,子类覆盖的仅仅是继承来的成员变量,并不改变原来父类的成员变量。

3)构造函数从基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。子类调用遵循就近原则:如果自己有则首先调用自己的函数;如果自己没有,父类存在相关接口则优先调用;如果父类不存在,则调用祖父类接口。

举例:(详见程序员面试宝典4--P134 and C++ prime(第五版)P550

 

知识点八、友元

一句话:能够访问类中的私有成员变量的非成员函数。使用友元函数时,需要注意以下几个方面:

1)必须在类中声明友元函数:关键字friend+友元函数原型;在类外部定义友元函数

2)友元函数不能直接访问类的成员,只能访问对象成员。所以,调用友元,需要指明对象。

3)友元函数不是成员函数,所以类与类之间的友元关系不能继承

//写一个程序,设计一个点类point,求两个点之间的距离(利用友元)

class point

{

public:

    point(float a=0.0f,float b=0.0f):x(a),y(b) {};

    friend float distance(point& left,point& right)

private:

    float x;

    float y;

};

friend float distance(point& left,point& right)

{

    return ((left.x-right.x)^2+(left.y-right.y)^2)^0.5;

}

 

知识点九、内存分类

C/C++编程中,经常需要操作的内存分为以下几类: 
栈区(stack:用于存放程序临时创建的局部变量,如函数的参数值、局部变量值等,由编译器自动分配释放。 
堆区(heap一般由程序员申请和释放。用于存放进程运行中被动态分配的内存段,大小不固定,可动态扩张或缩减。若程序员不释放,程序结束时,可能由操作系统回收,但最好还是由程序员释放。注意:它与数据结构中的堆是两回事,分配方式类似数据结构中的链表。 
全局区(静态区static全局变量和静态变量的存储是放在一起的。初始化的全局变量和静态变量在一块区域,未初始化的全局和未初始化的静态在邻近的另一块区域。程序结束后由系统释放。 
文字常量区
:存放字符串常量,程序结束后由系统释放。 
程序代码区:存放函数体内的二进制代码

heapstack的区别? 
1heap是堆,stack是栈。堆一般由程序员手动分配释放,栈是由操作系统自动分配释放。 
2stack的空间有限,在window下,栈是向低地址扩展的数据结构,是一块连续的内存区域,大小一般为2M;堆是向高地址扩展的数据结构,是不连续的内存区域,因为由系统用链表来存储空闲内存空间,堆的大小取决于系统的有效虚拟内存,有很大的自由存储区。 
3stack由系统自动分配,速度较快。Heapnew分配,一般速度比较慢,而且容易产生内存碎片。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值