zoukankan      html  css  js  c++  java
  • 专项训练知识点与错题整理-nowcoder-c++

    1- 来自:http://www.cskaoyan.com/thread-595813-1-1.html

    1.拷贝构造函数

    转自:https://www.cnblogs.com/alantu2018/p/8459250.html

    即自定义的特殊的构造函数,要求有两点:

    ①必须和类名同名。

    ②参数是本类的引用

    那么问题来了,这个函数在什么时候被调用呢?有三种情况:

    ①当函数参数为类的对象时

    ②当函数返回类型为类的对象时(它会首先赋值给一个临时变量然后返回,同时销毁自己。下面给个例子,感觉很受启发。)

    彡当一个对象需要另一个对象进行初始化时

    //(在进行类直接赋值的时候,这条是我自己总结的。)

    #include<iostream>
    using namespace std;
    class CExample
    {
    private:
        int a;
    public:
        //构造函数
        CExample(int b)
        {
         a=b;
            printf("constructor is called
    ");
        }
        //拷贝构造函数
        CExample(const CExample & c)
        {
         a=c.a;
            printf("copy constructor is called
    ");
        }
        //析构函数
        ~CExample()
        {
         cout<<"destructor is called
    ";
        }
        void Show()
        {
         cout<<a<<endl;
        }
    };
    CExample g_fun()
    {
        CExample temp(0);
        return temp;
    }
    int main()
    {
        
        g_fun();
        return 0;
    }
    return object

     重点来了:拷贝分为深拷贝和浅拷贝!

    1)默认是浅拷贝的,给出了一个例子,并不会对 静态数据成员进行操作;一般情况下只是进行简单的赋值,但是如果有动态申请空间的时候,就会出现问题:

    给出了一个例子;

    #include<iostream>
    #include<assert.h>
    using namespace std;
    class Rect
    {
    public:
        Rect()
        {
         p=new int(100);
        }
    
        ~Rect()
        {
         assert(p!=NULL);
            delete p;
        }
    private:
        int width;
        int height;
        int *p;
    };
    int main()
    {
        Rect rect1;
        Rect rect2(rect1);
        return 0;
    }
    Dynamic memory

    //此时两个p指向同一块内存,那么析构函数就会对一个内存空间释放两次!导致出现错误。 

    2)实现深拷贝函数

    #include<iostream>
    #include<assert.h>
    using namespace std;
    class Rect
    {
    public:
        Rect()
        {
         p=new int(100);
        }
    
        Rect(const Rect& r)//手动实现拷贝构造函数
        {
         width=r.width;
            height=r.height;
         p=new int(100);
            *p=*(r.p);//这个是使其存储的内容相同!
        }
    
        ~Rect()
        {
         assert(p!=NULL);
            delete p;
        }
    private:
        int width;
        int height;
        int *p;
    };
    int main()
    {
        Rect rect1;
        Rect rect2(rect1);
        return 0;
    }
    Deep Copy

     //手动实现拷贝构造函数

    3)防止默认拷贝发生

    防止出现默认拷贝了值,对于动态申请出错的现象,定义一个私有的拷贝构造函数但不必实现,即声明即可。

    #include<iostream>
    using namespace std;
    //防止按值传递
    class CExample
    {
    private:
        int a;
    
    public:
        //构造函数
        CExample(int b)
        {
            a = b;
            cout<<"creat: "<<a<<endl;
        }
    
    private:
        //拷贝构造函数,只是声明
        CExample(const CExample& C);
    
    public:
        ~CExample()
        {
            cout<< "delete: "<<a<<endl;
        }
    
        void Show ()
        {
            cout<<a<<endl;
        }
    };
    
    //????
    void g_Fun(CExample C)
    {
        cout<<"test"<<endl;
    }
    
    int main()
    {
        CExample test(1);
        g_Fun(test);   //按值传递将出错
    
        return 0;
    }
    Fobbid Default

    总结:在有指针的时候不能使用浅拷贝!会导致析构函数析构两次从而发生错误!

    二者主要区别就是在拷贝时,会在堆内存中申请额外空间来存储数据。

    细节也是重点:

    1.为什么拷贝构造函数是引用传递而不是值传递?

    //这个没看答案之前我还真是想不出来,但是你想想调用拷贝构造函数的情况包括作为函数参数传递,那么如果是这样的话,就会引起递归调用拷贝构造函数,造成无限递归!

    2.拷贝构造函数可以操作private类型的变量吗?

    拷贝构造函数就是一个特殊的构造函数,操作的还是自己的成员变量,所以不受private的限制。(其实这个还不太明白。)

    常见面试题,重点啊:

    1.构造函数能否重载,析构函数能否重载,为什么?

    构造函数可以重载(可以创建多个带参数的),析构函数不可以(只能有一个,不能带参数,无返回值,无类型)。

    2.析构函数为什么一般情况下要声明为虚函数?

    虚函数是实现多态的基础,当我们通过基类的指针是析构子类对象时候,如果不定义成虚函数,那只调用基类的析构函数,子类的析构函数将不会被调用。如果定义为虚函数,则子类父类的析构函数都会被调用

    2.  ::在C++种是什么意思?

    表示“域操作符”,比如在类A里给出了成员函数声明void f(),在类外进行定义的时候就要写成void A::f()。即表示是类A的成员函数。

    3.运算符重载

     有什么要求限制呢?

    1)不能改变原有操作符的操作数目;(双目与单目)

    2)不能改变原有操作符的结合顺序;

    3)不创建新的运算符。

    可以运用成员函数/友元函数进行重载:

    返回类型 operator 运算符(参数表){//实现}

    ①一般来说参数表中数目要和运算符数目相同,但是如果是成员函数那么就减少一个参数。

    ②参数表中至少有一个是类的成员,而不能都是int,int,int是内置类型。

    彡有显式调用和隐式调用:a+b/a.operator+(b);

    //对于双目运算符而言,只有一个形参即可,第一个是通过this指针传递的。

    4.c++种虚函数和纯虚函数?

    虚函数是为了实现多态,被virtual关键字修饰,虚函数必须实现;

    纯虚函数是针对那些不能生成对象的类,即抽象类。

    那么重点来了,在什么情况下使用纯虚函数?

    )在基类种抽象出一个方法,这个基类只能被继承,不能被实例化(避免它去实例化),并且方法要在派生类中实现

    class CShape
    {
    public:
        virtual void Show()=0;
    };

    5.C和C++有什么区别呢?

    1)C是面向过程的语言,C++是面向对象的语言,C++可以说是C的超集,包含C的特性

    2)C中动态内存管理是malloc/free,C++中是new/delete

    3)C中没有类,只有strcut,c++中有class,只是它的默认属性是private的,这是和C的区别

    4)C中不能进行函数重载,因为C++中函数进行名字修饰之后不仅包括函数名,而且包括每个参数的类型;但是C中只包括函数名

    5)C中没有引用

    5.1 malloc和new的区别

    malloc:是在堆中分配内存,并且是个函数,需要指明分配空间的大小,分配成功时返回void*,需要进行强制类型转换;

    new:是在自由存储区,既可以是堆,也可以是静态存储区;分配成功时返回指针,不成功时抛出异常。

    5.2 指针和引用的区别

    1)指针有自己的一块存储空间,而引用只是一个别名

    2)指针可以指向别的地址空间,但是引用只能是一个对象的引用,并且初始化时指针可以指向空,但是引用必须被初始化为一个已有对象

    3)还有在作为函数参数传递时的一些区别!

    6.静态全局变量和静态局部变量的区别

     静态局部变量:在函数内定义,在函数调用后就一直存在,生命周期是整个程序,但是访问范围仍然是在函数内,不是全局的。

    当要多次调用一个函数并且需要保存某些变量的值得时候可以使用!//这个着实没有想到。

    静态变量是存储在程序数据段,也就是静态内存分配,存放已经初始化的。

  • 相关阅读:
    (精华)将json数组和对象转换成List和Map(小龙哥和牛徳鹤的对话)
    优先队列底层实现是堆(heap)(操作系统进程调度)
    (透彻理解)最精锐代码::堆的三种基本操作新建-插入-删除
    (考研)读者写者问题(附代码)
    (考研)黑电吃苹果同步互斥问题(附代码)
    (考研)哲学家进餐问题(附代码)
    (考研)吸烟者问题(赋代码)
    (考研)PV操作和信号量
    01.第一章_C++ Primer学习笔记_开始
    C++学习笔记
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/9615860.html
Copyright © 2011-2022 走看看