设为首页 加入收藏

TOP

后端c++知识点总结(一)
2016-10-08 11:31:17 】 浏览:625
Tags:后端 ++知识点 总结

这一篇是C++的一些面试点的总结。

1、一个String类的完整实现必须很快速写出来(注意:赋值构造,operator=是关键)
  如果对C++String不熟悉的话,先看http://www.cplusplus.com/reference/去了解一下String类常用的方法,如果想了解C语言的实现,去看一下《C语言接口与实现》(十五章 低级字符串)。
  Scott Meyers在《effecive STL》中提到了std::string有多种实现方式。
  总结起来有三类(代码来源《Linux多线程服务端编程》):
  
  1. 无特殊处理,使用类似std::vector的数据结构。start到end之间存储数据,start到end_of_storage之间是容量大小,这样能减少扩容时数据复制的概率。后面两个成员变量还可以使用整数代替,如果字符串大小有限,可以使用u32等来表示end和end_of_storage,减小对象的大小。

class string{
    public:
        iterator begin()  { return start; }
        iterator end()    { return end;   }
    private:
        char* start;
        char* end;
        char* end_of_storage;   
};

  2. Copy-on-Write。对象里只放一个指针。
  

class string{
    struct Rep{
        size_t size;
        size_t capacity;
        size_t refcount;
        char* data[1];
    };
    char* start;
};

  3.短字符优化,利用字符串对象本身的空间存储短字符串,通常阈值是15字节。当定义比较短的字符串对象时,不需要再次申请分配内存。
  

class string{
    char* start;
    size_t size;
    static const int kLocalSize = 15;
    union{
        char buffer[kLocalSize+1];
        size_t capacity;
    }data;
};

这里给出关键的赋值函数

/*
如下为CMyString的声明,请为该类型添加赋值运算符 
*/
#include
  
   
#include
   
     class CMyString{ public: CMyString(char *m_pData=NULL); CMyString(const CMyString& str); ~CMyString(void); CMyString& operator=(const CMyString& rhs); private: char * m_pData; }; /* 考察几个知识点: 1.返回值类型为 X& 解决连续赋值时的左值问题 2.使用const &提高效率,避免传参数时的拷贝构造 3.在赋值和拷贝构造函数中,应该先释放原对象空间,重新申请, 避免两个指针指向同一内存,浅拷贝问题,避免内存泄漏。 4.可以使用swap的写法,先构造局部变量,在作用域之外释放掉。 5.字符串申请空间时。应该+1,为结束符'\0'留位置。 6.strcpy应该使用更安全的strncpy代替,避免缓冲区溢出。 */ CMyString& CMyString::operator=(const CMyString& rhs){ if(this!=&rhs){ delete []m_pData; m_pData=NULL; m_pData=(char *)malloc(strlen(rhs.m_pData)+1); strcpy(m_pData,rhs.m_pData); //可用构造后交换防止异常 /* CMyString strTemp(rhs); char *pTemp=strTemp.m_pData; strTemp.m_pData=m_pData; m_pData=pTemp;*/ } return *this; }
   
  

2、虚函数的作用和实现原理(必问必考,实现原理必须很熟)

  这个问题在《深度探索C++对象模型》中有非常详细的讲解。
  这里只简单的说一下原理。如果你不知道虚函数和多态的概念,先去看看《C++primer》之类的语言书。
  首先,如果一个类中含有虚函数,那么每一个类就会有一个virtual table,这个表中放置着各个虚函数的地址。然后每一个类对象(就是实例)中会被安插一个由编译器产生的指针vptr,该指针指向一个virtual table,class所关联的type_info,会放在vitrual table的第一个slot中,用来表示class的类型。
  识别多态的方式是查看类中是否有虚函数,实现就是通过指针取用相应的函数。例如
  

class Point{
    public:
        virtual ~Point();
        //...其他操作
        virtual float z() const { return 0; }
};
class Point3d{
    public:
        float z const{ return _z; }
    protected:
        float _z;

};
Point *ptr;
ptr = new Point3d;
ptr ->z();

当我们调用z()的时候,并不知道ptr所指向的对象的真正类型,这个是在执行期确定的。但是我们可以知道ptr可以访问到改对象的virtual table。

虽然不知道具体哪一个z()实例会被调用,是基类的,还是继承类的,但是我们可以确定每一个z()函数地址所存放的slot,它在virtual table中的位置是确定的。

通过这些信息编译器可以在编译器将该调用转化成:

(*ptr->vptr[4])(ptr);

通过执行期获取到ptr的具体类型,就实现了多态。

  上面是比较美好的单一继承的情况,多继承下需要考虑this指针的调整问题,可以选择使用thunk技术(以适当offset调整this指针,跳到virtual function 去),或者像cfont编译器的做法一样,将每一个virtual table slot调整成含有offset的集合体。
  Derived class中会含有额外的virtual table来识别base1,base2…baseN。每一个virtual table的slot中放置原始的地址或者thunk地址。
  虚拟继承还需要考虑到virtual base类的offset调整,已经繁琐到让人不愿谈了。
  

3、sizeof一个类求大小(注意成员变量,函数,虚函数,继承等等对大小的影响)

直接给一个例子,大致覆盖一下这些情况。

#include 
  
   
using namespace std;
class X{};
class Y:public virtual X{};
class Z:public virtual X{};
class A:public Y,public Z{};
class Point{
  private:
    char a;
    char b;
    char c;
    //注释掉d,大小为3
    float d;
};
class Point2d{
    public:
        virtual float getX(){ return x;}
        virtual float getY(){ return y;}
    private:
        floa
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇c++知识复习2.0 下一篇C++研发面试笔记:基本数据结构-..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目