1.面向对象三大特性

继承:

一个对象直接使用另一个对象的属性和方法。
优点:1.减少重复的代码。
      2.继承是多态的前提。
      3.继承增加了类的耦合性。
缺点:1.继承在编译时刻就定义了,无法在运行时刻改变父类继承的实现
      2.父类通常至少定义了子类的部分行为,父类的改变都可能影响子类的行为;
      3.如果继承下来的子类不适合解决新问题,父类必须重写或替换,那么这种依赖关系就限制了灵活性,最终限制了复用性。
虚继承:为了解决多重继承中的二义性问题,它维护了一张虚基类表。

封装:

隐藏对象的属性和实现细节,仅仅对外提供接口和方法。

多态:

C++中有两种多态,称为 动多态(运行期多态) 和 静多态(编译期多态) ,而 静多态主要通过模板来实现,宏也是实现静多态的一种途径 。 动多态在C++中是通过虚函数实现的 ,即在基类中存在一些接口(一般为纯虚函数),子类必须重载这些接口。这样通过使用基类的指针或者引用指向子类的对象,就可以实现调用子类对应的函数的功能。动多态的函数调用机制是执行期才能进行确定,所以它是动态的。
接口的多种不同实现方式即为多态。
 
2.类的访问权限
private:
被private限定符修饰的成员变量只能被该类的方法和友元函数访问,子类函数无法访问,在这三个限定符中封装程度是最高的
继承:父类  public/protected/private      子类 private/private/private
public:
被public限定符所修饰的成员变量和函数可以被类的函数、子类的函数、友元函数,也可以由类的对象来访问
继承:父类  public/protected/private      子类 public/protected/private
protected:
protected限定符修饰的成员变量和成员函数可以被该类的成员函数访问,但是不能被类对象所访问
继承:父类  public/protected/private      子类 protected/protected/private
 
3.类的构造函数 析构函数 赋值函数 拷贝函数
 
4.移动构造函数与拷贝构造函数的对比
 //拷贝构造函数  深拷贝
A(A& t)
{
    if(t.text!=NULL)
    {
        int len=strlen(t.text);
        text=new char[len+1];
        strcpy(text,t.text);
    }
}
//移动构造函数  浅拷贝
A(A&& t)
{
    if(t.text!=NULL)
    {
        text=t.text;
        t.text=NULL;
    }
}
 
5.深拷贝和浅拷贝的区别
深拷贝开辟了新的内存区域
浅拷贝只是单纯赋值
 
6.内存分区
全局区
全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
堆区
就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
栈区
就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。
常量区
这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)
代码区
存放函数体的二进制代码,由操作系统进行管理的
 
7.空类有哪些函数,空类的大小
默认构造函数、默认拷贝构造函数、默认析构函数、默认赋值运算符 这四个是我们通常大都知道的。但是除了这四个,还有两个,那就是取址运算符和 取址运算符 const
空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1
 
8.c++和c的区别
  • 1.函数默认值  c++可以为形参赋值(不传参)int FUM( int  a=10   )
  • 2.inline内联函数

    它的具体做法和宏非常相似,也是在调用处直接将代码展开,只不过宏它是在预编译阶段展开,而内联函数是在 编译阶段进行处理的。同时,宏作为预处理并不进行类型检查,而inline函数是要进行类型检查的,也就可以称作“更安全的宏”。

    内联函数和普通函数的区别:内联函数没有栈帧的开辟回退,一般我们直接把内联函数写在头文件中,include之后就可以使用,由于调用时直接代码展开所以我们根本不需要担心什么重定义的问题——它连符号都没有生成当然不会所谓重定义了。普通函数生成符号,内联函数不会生成符号。

    关于inline还需要注意的一点是,我们在使用它的时候往往是用来替换函数体非常小(1~5行代码)的函数的。这种情况下函数的堆栈开销相对函数体大小来说就非常大了,这种情况使用内联函数可以大大提高效率。相反如果是一个需要很多代码才能实现的函数,则不适合使用。一是此时函数堆栈调用开销与函数体相比已经是微不足道了,二是大量的代码直接展开的话会给调试带来很大的不便。三是如果代码体达到一个阈值,编译器会将它变成普通函数。

    同时,递归函数不能声明为inline函数。说到底inline只是对编译器的建议,最终能否成功也不一定。同时,我们平常生成的都是debug版本,在这个版本下inline是不起作用的。只有生成release版时才会起作用。

  • 3.函数重载                                                                                                                                                                                                                                                                                                               C++生成函数符号则考虑了函数名、参数个数、参数类型。需要注意的是函数的返回值并不能作为函数重载的依据,也就是说int sum和double sum这两个函数是不能构成重载的!我们的函数重载也属于多态的一种,这就是所谓的静多态。静多态:函数重载,函数模板动多态(运行时的多态):继承中的多态(虚函数)。
  • 4.const
  •  真正的常量。定义的时候必须初始化,可以用作数组的下标。const在C++中的编译规则是替换(和宏很像),所以它被看作是真正的常量。 
  • 5.引用
  • 6.malloc,free && new,delete
  • 7.作用域

9.struct和class的区别

struct能包含成员函数吗? 能!
struct能继承吗? 能!!
struct能实现多态吗? 能!!!
既然这些它都能实现,那它和class还能有什么区别?

最本质的一个区别就是默认的访问控制:
默认的继承访问权限
struct是public的,class是private的。
struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的

 

10.struct 对齐

1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.

等你看完此3条原则,2分钟已经过去,抓紧时间,实战3分钟:

typedef struct bb
{
 int id;            //[0]....[3]
 double weight;     //[8].....[15]      原则1
 float height;     //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
 char name[2];    //[0],[1]
 int id;        //[4]...[7]          原则1

 double score;    //[8]....[15]    
 short grade;   //[16],[17]        
 BB b;            //[24]......[47]          原则2
}AA;

int main()
{
  AA a;
 cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}

结果是

48 24