精华内容
下载资源
问答
  • JDBC连接方式有哪几种

    2013-12-01 13:55:00
    2011-05-10目前比较常见的JDBC驱动程序可分为以下四个种类:(1)JDBC-ODBC桥加ODBC...因此,这种类型的驱动程序最适合于企业网(这种网络上客户机的安装不是主要问题),或者是用Java编写的三层结构的应用程序服...
    2011-05-10

    目前比较常见的JDBC驱动程序可分为以下四个种类: 

    (1)JDBC-ODBC桥加ODBC驱动程序 

    JavaSoft桥产品利用ODBC驱动程序提供JDBC访问。注意,必须将ODBC二进制代码(许多情况下还包括数据库客户机代码)加载到使用该驱动程序的每个客户机上。因此,这种类型的驱动程序最适合于企业网(这种网络上客户机的安装不是主要问题),或者是用Java编写的三层结构的应用程序服务器代码。 

    (2)本地API 

    这种类型的驱动程序把客户机API上的JDBC调用转换为Oracle、Sybase、Informix、DB2或其它DBMS的调用。注意,象桥驱动程序一样,这种类型的驱动程序要求将某些二进制代码加载到每台客户机上。 

    (3)JDBC网络纯Java驱动程序 

    这种驱动程序将JDBC转换为与DBMS无关的网络协议,之后这种协议又被某个服务器转换为一种DBMS协议。这种网络服务器中间件能够将它的纯Java客户机连接到多种不同的数据库上。所用的具体协议取决于提供者。通常,这是最为灵活的JDBC驱动程序。有可能所有这种解决方案的提供者都提供适合于Intranet用的产品。为了使这些产品也支持Internet访问,它们必须处理Web所提出的安全性、通过防火墙的访问等方面的额外要求。几家提供者正将JDBC驱动程序加到他们现有的数据库中间件产品中。 

    (4)本地协议纯Java驱动程序 

    这种类型的驱动程序将JDBC调用直接转换为DBMS所使用的网络协议。这将允许从客户机机器上直接调用DBMS服务器,是Intranet访问的一个很实用的解决方法。由于许多这样的协议都是专用的,因此数据库提供者自己将是主要来源,有几家提供者已在着手做这件事了。 

    据专家预计第(3)、(4)类驱动程序将成为从JDBC访问数据库的首方法。第(1)、(2)类驱动程序在直接的纯Java驱动程序还没有上市前会作为过渡方案来使用。对第(1)、(2)类驱动程序可能会有一些变种,这些变种要求有连接器,但通常这些是更加不可取的解决方案。第(3)、(4)类驱动程序提供了Java的所有优点,包括自动安装(例如,通过使用JDBC驱动程序的appletapplet来下载该驱动程序)。 

    转载于:https://www.cnblogs.com/huapox/p/3516329.html

    展开全文
  • 1、前馈神经网络:是最常见类型,第一层为输入,最后一层为输出。如果多个隐藏层,则称为“深度”神经网络。它能够计算出一系列事件间相似转变的变化,每层神经元的活动是下一层的非线性函数。 2、循环神经网络...

    神经网络是一种通用机器学习模型,是一套特定的算法集,在机器学习领域掀起了一场变革,本身就是普通函数的逼近,可以应用到任何机器学习输入到输出的复杂映射问题。一般来说,神经网络架构可分为3类:

    1、前馈神经网络:是最常见的类型,第一层为输入,最后一层为输出。如果有多个隐藏层,则称为“深度”神经网络。它能够计算出一系列事件间相似转变的变化,每层神经元的活动是下一层的非线性函数。

    2、循环神经网络:各节点之间构成循环图,可以按照箭头的方向回到初始点。循环神经网络具有复杂的动态,难以训练,它模拟连续数据,相当于每个时间片段具有一个隐藏层的深度网络,除了在每个时间片段上使用相同的权重,也有输入。网络可以记住隐藏状态的信息,但是很难用这点来训练网络。

    3、对称连接网络:和循环神经网络一样,但单元间的连接是对称的(即在两个方向的连接权重相同),它比循环神经网络更容易分析,但是功能受限。没有隐藏单元的对称连接的网络被称为“Hopfiels网络”,有隐藏单元的对称连接的网络则被称为“波兹曼机器”。

    什么是神经网络,深度神经网络怎么分类的,主要是做什么的?
    人工神经网络的架构,主要由哪几部分组成?
    人工神经网络是什么,人工神经网络的的优点有哪些?

    多智时代-人工智能大数据学习入门网站|人工智能、大数据、物联网云计算的学习交流网站

    多智时代-人工智能大数据学习入门网站|人工智能、大数据、云计算、物联网的学习服务的好平台
    展开全文
  • 问题4-11:的书(如[COME06])将IP地址分为前缀和后缀两大部分,它们和网络号字段及主机号字段什么关系? 问题4-12:IP地址中的前缀和后缀最大的不同是什么? 问题4-13:IP数据报中的数据部分的长度是可变的(即...
  • C/C++常见面试知识点总结附面试真题----20210302更新

    万次阅读 多人点赞 2018-09-19 22:47:57
    1. C/C++内存有哪几种类型? C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区...

    以下内容部分整理自网络,部分为自己面试的真题。

    第一部分:计算机基础

    1. C/C++内存有哪几种类型?

    C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区(new)一说。
    全局变量、static变量会初始化为缺省值,而堆和栈上的变量是随机的,不确定的。

    2. 堆和栈的区别?

    • 1).堆存放动态分配的对象——即那些在程序运行时动态分配的对象,比如 new 出来的对象,其生存期由程序控制;
    • 2).栈用来保存定义在函数内的非static对象,如局部变量,仅在其定义的程序块运行时才存在;
    • 3).静态内存用来保存static对象,类static数据成员以及定义在任何函数外部的变量,static对象在使用之前分配,程序结束时销毁;
    • 4).栈和静态内存的对象由编译器自动创建和销毁。

    3. 堆和自由存储区的区别?

    总的来说,堆是C语言和操作系统的术语,是操作系统维护的一块动态分配内存;自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。他们并不是完全一样。
    从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。

    4. 程序编译的过程?

    程序编译的过程中就是将用户的文本形式的源代码(c/c++)转化成计算机可以直接执行的机器代码的过程。主要经过四个过程:预处理、编译、汇编和链接。具体示例如下。
    一个hello.c的c语言程序如下。

    #include <stdio.h>
    int main()
    {
        printf("happy new year!\n");
        return 0;
    }
    

    其编译过程如下:
    在这里插入图片描述

    5. 计算机内部如何存储负数和浮点数?

    负数比较容易,就是通过一个标志位和补码来表示。
    对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit,double数据占用64bit,我们在声明一个变量float f= 2.25f的时候,是如何分配内存的呢?如果胡乱分配,那世界岂不是乱套了么,其实不论是float还是double在存储方式上都是遵从IEEE的规范的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。更多可以参考浮点数表示。
    无论是单精度还是双精度在存储中都分为三个部分:

    • 1). 符号位(Sign) : 0代表正,1代表为负
    • 2). 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
    • 3). 尾数部分(Mantissa):尾数部分
      其中float的存储方式如下图所示:
      在这里插入图片描述
      而双精度的存储方式如下图:
      在这里插入图片描述

    6. 函数调用的过程?

    如下结构的代码,

    int main(void)
    {
      ...
      d = fun(a, b, c);
      cout<<d<<endl;
      ...
      return 0;
    }
    

    调用fun()的过程大致如下:

    • main()========
    • 1).参数拷贝(压栈),注意顺序是从右到左,即c-b-a;
    • 2).保存d = fun(a, b, c)的下一条指令,即cout<<d<<endl(实际上是这条语句对应的汇编指令的起始位置);
    • 3).跳转到fun()函数,注意,到目前为止,这些都是在main()中进行的;
    • fun()=====
    • 4).移动ebp、esp形成新的栈帧结构;
    • 5).压栈(push)形成临时变量并执行相关操作;
    • 6).return一个值;
    • 7).出栈(pop);
    • 8).恢复main函数的栈帧结构;
    • 9).返回main函数;
    • main()========
    • 。。。

    7. 左值和右值

    不是很严谨的来说,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。举例来说我们定义的变量 a 就是一个左值,而malloc返回的就是一个右值。或者左值就是在程序中能够寻值的东西,右值就是一个具体的真实的值或者对象,没法取到它的地址的东西(不完全准确),因此没法对右值进行赋值,但是右值并非是不可修改的,比如自己定义的class, 可以通过它的成员函数来修改右值。

    归纳一下就是:

    • 可以取地址的,有名字的,非临时的就是左值
    • 不能取地址的,没有名字的,临时的,通常生命周期就在某个表达式之内的就是右值

    8. 什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误?

    用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露。

    • 1). 使用的时候要记得指针的长度.
    • 2). malloc的时候得确定在那里free.
    • 3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.
    • 4). 动态分配内存的指针最好不要再次赋值.
    • 5). 在C++中应该优先考虑使用智能指针.

    第二部分:C v.s. C++

    1. C和C++的区别?

    • 1). C++是C的超集;
    • 2). C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

    2. int fun() 和 int fun(void)的区别?

    这里考察的是c 中的默认类型机制。

    • 在c中,int fun() 会解读为返回值为int(即使前面没有int,也是如此,但是在c++中如果没有返回类型将报错),输入类型和个数没有限制, 而int fun(void)则限制输入类型为一个void。
    • 在c++下,这两种情况都会解读为返回int类型,输入void类型。

    3. const 有什么用途

    主要有三点:

    • 1).定义只读变量,或者常量(只读变量和常量的区别参考下面一条);
    • 2).修饰函数的参数和函数的返回值;
    • 3).修饰函数的定义体,这里的函数为类的成员函数,被const修饰的成员函数代表不能修改成员变量的值,因此const成员函数只能调用const成员函数;
    • 4).只读对象。只读对象只能调用const成员函数。
    class Screen {
    public:
    const char cha; //const成员变量
    char get() const; //const成员函数
    };
    
    const Screen screen; //只读对象
    

    4. 在C中用const 能定义真正意义上的常量吗?C++中的const呢?

    不能。c中的const仅仅是从编译层来限定,不允许对const 变量进行赋值操作,在运行期是无效的,所以并非是真正的常量(比如通过指针对const变量是可以修改值的),但是c++中是有区别的,c++在编译时会把const常量加入符号表,以后(仍然在编译期)遇到这个变量会从符号表中查找,所以在C++中是不可能修改到const变量的。
    补充:

    • 1). c中的局部const常量存储在栈空间,全局const常量存在只读存储区,所以全局const常量也是无法修改的,它是一个只读变量。
    • 2). 这里需要说明的是,常量并非仅仅是不可修改,而是相对于变量,它的值在编译期已经决定,而不是在运行时决定。
    • 3).c++中的const 和宏定义是有区别的,宏是在预编译期直接进行文本替换,而const发生在编译期,是可以进行类型检查和作用域检查的。
    • 4).c语言中只有enum可以实现真正的常量。
    • 5). c++中只有用字面量初始化的const常量会被加入符号表,而变量初始化的const常量依然只是只读变量。
    • 6). c++中const成员为只读变量,可以通过指针修改const成员的值,另外const成员变量只能在初始化列表中进行初始化。

    下面我们通过代码来看看区别。
    同样一段代码,在c编译器下,打印结果为*pa = 4, 4
    在c++编译下打印的结果为 *pa = 4, 8

    int main(void)
    {
        const int a = 8;
        int *pa = (int *)&a;
        *pa = 4;
        printf("*pa = %d, a = %d", *pa, a);
        return 0;
    }
    

    另外值得一说的是,由于c++中const常量的值在编译期就已经决定,下面的做法是OK的,但是c中是编译通不过的。

    
    int main(void)
    {
        const int a = 8;
        const int b = 2;
        int array[a+b] = {0};
        return 0;
    }
    

    5. 宏和内联(inline)函数的比较?

    • 1). 首先宏是C中引入的一种预处理功能;
    • 2). 内联(inline)函数是C++中引用的一个新的关键字;C++中推荐使用内联函数来替代宏代码片段;
    • 3). 内联函数将函数体直接扩展到调用内联函数的地方,这样减少了参数压栈,跳转,返回等过程;
    • 4). 由于内联发生在编译阶段,所以内联相较宏,是有参数检查和返回值检查的,因此使用起来更为安全;
    • 5). 需要注意的是, inline会向编译期提出内联请求,但是是否内联由编译期决定(当然可以通过设置编译器,强制使用内联);
    • 6). 由于内联是一种优化方式,在某些情况下,即使没有显示的声明内联,比如定义在class内部的方法,编译器也可能将其作为内联函数。
    • 7). 内联函数不能过于复杂,最初C++限定不能有任何形式的循环,不能有过多的条件判断,不能对函数进行取地址操作等,但是现在的编译器几乎没有什么限制,基本都可以实现内联。
      更多请参考inline关键字

    6. C++中有了malloc / free , 为什么还需要 new / delete?

    • 1). malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
    • 2). 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
      由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
      最后补充一点体外话,new 在申请内存的时候就可以初始化(如下代码), 而malloc是不允许的。另外,由于malloc是库函数,需要相应的库支持,因此某些简易的平台可能不支持,但是new就没有这个问题了,因为new是C++语言所自带的运算符。
    int *p = new int(1);
    

    特别的,在C++中,如下的代码,用new创建一个对象(new 会触发构造函数, delete会触发析构函数),但是malloc仅仅申请了一个空间,所以在C++中引入new和delete来支持面向对象。

    #include <cstdlib>
    class Test
    {
        ...
    }
    
    Test* pn = new Test;
    Test* pm = (Test*)malloc(sizeof(Test));
    

    7. C和C++中的强制类型转换?

    C中是直接在变量或者表达式前面加上(小括号括起来的)目标类型来进行转换,一招走天下,操作简单,但是由于太过直接,缺少检查,因此容易发生编译检查不到错误,而人工检查又及其难以发现的情况;而C++中引入了下面四种转换:

    • 1). static_cast
      a. 用于基本类型间的转换
      b. 不能用于基本类型指针间的转换
      c. 用于有继承关系类对象间的转换和类指针间的转换
    • 2). dynamic_cast
      a. 用于有继承关系的类指针间的转换
      b. 用于有交叉关系的类指针间的转换
      c. 具有类型检查的功能
      d. 需要虚函数的支持
    • 3). reinterpret_cast
      a. 用于指针间的类型转换
      b. 用于整数和指针间的类型转换
    • 4). const_cast
      a. 用于去掉变量的const属性
      b. 转换的目标类型必须是指针或者引用
      在C++中,普通类型可以通过类型转换构造函数转换为类类型,那么类可以转换为普通类型吗?答案是肯定的。但是在工程应用中一般不用类型转换函数,因为无法抑制隐式的调用类型转换函数(类型转换构造函数可以通过explicit来抑制其被隐式的调用),而隐式调用经常是bug的来源。实际工程中替代的方式是定义一个普通函数,通过显式的调用来达到类型转换的目的。
    class test{
        int m_value;
        ...
    public:
        operator int()  //类型转换函数
        {
            return m_value;
        }
    
        int toInt() //显示调用普通函数来实现类型转换
        {
            return m_value
        }
    };
    
    int main()
    {
        ...
        test a(5);
        int i = a;
        ...
    
        return 0;
    }
    

    8. static 有什么用途

    • 1). 静态(局部/全局)变量
    • 2). 静态函数
    • 3). 类的静态数据成员
    • 4). 类的静态成员函数

    9. 类的静态成员变量和静态成员函数各有哪些特性?

    静态成员变量

    • 1). 静态成员变量需要在类内声明(加static),在类外初始化(不能加static),如下例所示;
    • 2). 静态成员变量在类外单独分配存储空间,位于全局数据区,因此静态成员变量的生命周期不依赖于类的某个对象,而是所有类的对象共享静态成员变量;
    • 3). 可以通过对象名直接访问公有静态成员变量;
    • 4). 可以通过类名直接调用公有静态成员变量,即不需要通过对象,这一点是普通成员变量所不具备的。
    class example{
    private:
    static int m_int; //static成员变量
    };
    
    int example::m_int = 0; //没有static
    
    cout<<example::m_int; //可以直接通过类名调用静态成员变量
    

    静态成员函数

    • 1). 静态成员函数是类所共享的;
    • 2). 静态成员函数可以访问静态成员变量,但是不能直接访问普通成员变量(需要通过对象来访问);需要注意的是普通成员函数既可以访问普通成员变量,也可以访问静态成员变量;
    • 3). 可以通过对象名直接访问公有静态成员函数;
    • 4). 可以通过类名直接调用公有静态成员函数,即不需要通过对象,这一点是普通成员函数所不具备的。
    class example{
    private:
    static int m_int_s; //static成员变量
    int m_int;
    static int getI() //静态成员函数在普通成员函数前加static即可
    {
      return m_int_s; //如果返回m_int则报错,但是可以return d.m_int是合法的
    }
    };
    
    cout<<example::getI(); //可以直接通过类名调用静态成员变量
    

    10. 在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?

    C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同,假设某个函数原型为:

              void foo(int x, int y);
    

    该函数被C编译器编译后在库中的名字为 _foo, 而C++编译器则会产生像: _foo_int_int 之类的名字。为了解决此类名字匹配的问题,C++提供了C链接交换指定符号 extern “C”。

    11. 头文件中的 ifndef/define/endif 是干什么用的? 该用法和 program once 的区别?

    相同点:
    它们的作用是防止头文件被重复包含。
    不同点

    • 1). ifndef 由语言本身提供支持,但是 program once 一般由编译器提供支持,也就是说,有可能出现编译器不支持的情况(主要是比较老的编译器)。
    • 2). 通常运行速度上 ifndef 一般慢于 program once,特别是在大型项目上, 区别会比较明显,所以越来越多的编译器开始支持 program once。
    • 3). ifndef 作用于某一段被包含(define 和 endif 之间)的代码, 而 program once 则是针对包含该语句的文件, 这也是为什么 program once 速度更快的原因。
    • 4). 如果用 ifndef 包含某一段宏定义,当这个宏名字出现“撞车”时,可能会出现这个宏在程序中提示宏未定义的情况(在编写大型程序时特性需要注意,因为有很多程序员在同时写代码)。相反由于program once 针对整个文件, 因此它不存在宏名字“撞车”的情况, 但是如果某个头文件被多次拷贝,program once 无法保证不被多次包含,因为program once 是从物理上判断是不是同一个头文件,而不是从内容上。

    12. 当i是一个整数的时候++i和i++那个更快一点?i++和++i的区别是什么?

    答:理论上++i更快,实际与编译器优化有关,通常几乎无差别。

    //i++实现代码为:
    int operator++(int)
    {
        int temp = *this;
        ++*this;
        return temp;
    }//返回一个int型的对象本身
    
    // ++i实现代码为:
    int& operator++()
    {
        *this += 1;
        return *this;
    }//返回一个int型的对象引用
    

    i++和++i的考点比较多,简单来说,就是i++返回的是i的值,而++i返回的是i+1的值。也就是++i是一个确定的值,是一个可修改的左值,如下使用:

    cout << ++(++(++i)) << endl;
    cout << ++ ++i << endl;
    

    可以不停的嵌套++i。
    这里有很多的经典笔试题,一起来观摩下:

    int main()
    {
        int i = 1;
        printf("%d,%d\n", ++i, ++i);    //3,3
        printf("%d,%d\n", ++i, i++);    //5,3
        printf("%d,%d\n", i++, i++);    //6,5
        printf("%d,%d\n", i++, ++i);    //8,9
        system("pause");
        return 0;
    }
    

    首先是函数的参数入栈顺序从右向左入栈的,计算顺序也是从右往左计算的,不过都是计算完以后再进行的压栈操作:
    对于第1个printf,首先执行++i,返回值是i,这时i的值是2,再次执行++i,返回值是i,得到i=3,将i压入栈中,此时i为3,也就是压入3,3;
    对于第2个printf,首先执行i++,返回值是原来的i,也就是3,再执行++i,返回值是i,依次将3,5压入栈中得到输出结果
    对于第3个printf,首先执行i++,返回值是5,再执行i++返回值是6,依次将5,6压入栈中得到输出结果
    对于第4个printf,首先执行++i,返回i,此时i为8,再执行i++,返回值是8,此时i为9,依次将i,8也就是9,8压入栈中,得到输出结果。
    上面的分析也是基于VS搞的,不过准确来说函数多个参数的计算顺序是未定义的(the order of evaluation of function arguments are undefined)。笔试题目的运行结果随不同的编译器而异。

    第三部分:数组、指针 & 引用

    1. 指针和引用的区别?

    相同点:

    • 1). 都是地址的概念;
    • 2). 都是“指向”一块内存。指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名;
    • 3). 引用在内部实现其实是借助指针来实现的,一些场合下引用可以替代指针,比如作为函数形参。
    不同点:
    • 1). 指针是一个实体,而引用(看起来,这点很重要)仅是个别名;
    • 2). 引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
    • 3). 引用不能为空,指针可以为空;
    • 4). “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
    • 5). 指针和引用的自增(++)运算意义不一样;
    • 6). 引用是类型安全的,而指针不是 (引用比指针多了类型检查)
    • 7). 引用具有更好的可读性和实用性。

    2. 引用占用内存空间吗?

    如下代码中对引用取地址,其实是取的引用所对应的内存空间的地址。这个现象让人觉得引用好像并非一个实体。但是引用是占用内存空间的,而且其占用的内存和指针一样,因为引用的内部实现就是通过指针来完成的。

    比如 Type& name; <===> Type* const name。

    int main(void)
    {
            int a = 8;
            const int &b = a;
            int *p = &a;
            *p = 0;
            cout<<a; //output 0
        return 0;
    }
    

    3. 三目运算符

    在C中三目运算符(? :)的结果仅仅可以作为右值,比如如下的做法在C编译器下是会报错的,但是C++中却是可以是通过的。这个进步就是通过引用来实现的,因为下面的三目运算符的返回结果是一个引用,然后对引用进行赋值是允许的。

    int main(void)
    {
            int a = 8;
            int b = 6;
            (a>b ? a : b) = 88;
            cout<<a; //output 88
        return 0;
    }
    

    4. 指针数组和数组指针的区别

    数组指针,是指向数组的指针,而指针数组则是指该数组的元素均为指针。

    • 数组指针,是指向数组的指针,其本质为指针,形式如下。如 int (*p)[10],p即为指向数组的指针,()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。数组指针是指向数组首元素的地址的指针,其本质为指针,可以看成是二级指针。
    类型名 (*数组标识符)[数组长度]
    
    • 指针数组,在C语言和C++中,数组元素全为指针的数组称为指针数组,其中一维指针数组的定义形式如下。指针数组中每一个元素均为指针,其本质为数组。如 int *p[n], []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
    类型名 *数组标识符[数组长度]
    

    5. 左值引用与右值引用

    该部分主要摘自:c++ 学习笔记

    左值引用就是我们通常所说的引用,如下所示。左值引用通常可以看作是变量的别名。

    type-id & cast-expression 
    
    // demo
    int a = 10
    int &b = a
    
    int &c = 10	// 错误,无所对一个立即数做引用
    
    const int &d = 10	// 正确, 常引用引用常数量是ok的,其等价于 const int temp = 10; const int &d = temp	
    

    右值引用是 C++11 新增的特性,其形式如下所示。右值引用用来绑定到右值,绑定到右值以后本来会被销毁的右值的生存期会延长至与绑定到它的右值引用的生存期。

    type-id && cast-expression  
    
    // demo
    int &&var = 10;	// ok
    
    int a = 10
    int &&b = a	// 错误, a 为左值
    
    int &&c = var	// 错误,var 为左值
    
    int &&d = move(a)	// ok, 通过move得到左值的右值引用
    

    在汇编层面右值引用做的事情和常引用是相同的,即产生临时量来存储常量。但是,唯一 一点的区别是,右值引用可以进行读写操作,而常引用只能进行读操作。

    6. 右值引用的意义

    • 右值引用支持移动语义的实现,可以减少拷贝,提升程序的执行效率。

      下面的代码时没有采用右值引用时的实现。

      class Stack
      {
      public:
          // 构造
          Stack(int size = 1000) 
      	:msize(size), mtop(0)
          {
      	cout << "Stack(int)" << endl;
      	mpstack = new int[size];
          }
      	
          // 析构
          ~Stack()
          {
      	cout << "~Stack()" << endl;
      	delete[]mpstack;
      	mpstack = nullptr;
          }
      	
          // 拷贝构造
          Stack(const Stack &src)
      	:msize(src.msize), mtop(src.mtop)
          {
      	cout << "Stack(const Stack&)" << endl;
      	mpstack = new int[src.msize];
      	for (int i = 0; i < mtop; ++i) {
      	    mpstack[i] = src.mpstack[i];
      	}
          }
      	
          // 赋值重载
          Stack& operator=(const Stack &src)
          {
      	cout << "operator=" << endl;
      	if (this == &src)
           	    return *this;
      
      	delete[]mpstack;
      
      	msize = src.msize;
      	mtop = src.mtop;
      	mpstack = new int[src.msize];
      	for (int i = 0; i < mtop; ++i) {
      	    mpstack[i] = src.mpstack[i];
      	}
      	return *this;
          }
      
          int getSize() 
          {
      	return msize;
          }
      private:
          int *mpstack;
          int mtop;
          int msize;
      };
      
      Stack GetStack(Stack &stack)
      {
          Stack tmp(stack.getSize());
          return tmp;
      }
      
      int main()
      {
          Stack s;
          s = GetStack(s);
          return 0;
      }
      

      运行结果如下。

      Stack(int)             // 构造s
      Stack(int)             // 构造tmp
      Stack(const Stack&)    // tmp拷贝构造main函数栈帧上的临时对象
      ~Stack()               // tmp析构
      operator=              // 临时对象赋值给s
      ~Stack()               // 临时对象析构
      ~Stack()               // s析构
      

      执行代码的过程中调用拷贝构造,将内存中的内容逐个拷贝,在 C++ 11 中可以借助右值引用实现移动拷贝构造和移动赋值来解决这个问题。

      Stack(Stack &&src)
          :msize(src.msize), mtop(src.mtop)
      {
          cout << "Stack(Stack&&)" << endl;
      
          /*此处没有重新开辟内存拷贝数据,把src的资源直接给当前对象,再把src置空*/
          mpstack = src.mpstack;  
          src.mpstack = nullptr;
      }
      
      // 带右值引用参数的赋值运算符重载函数
      Stack& operator=(Stack &&src)
      {
          cout << "operator=(Stack&&)" << endl;
      
          if(this == &src)
              return *this;
      	    
          delete[]mpstack;
      
          msize = src.msize;
          mtop = src.mtop;
      
          /*此处没有重新开辟内存拷贝数据,把src的资源直接给当前对象,再把src置空*/
          mpstack = src.mpstack;
          src.mpstack = nullptr;
      
          return *this;
      }
      

      执行结果如下。可以看到,在有拷贝构造和移动拷贝构造函数的时候,优先调用了移动拷贝构造和移动赋值。在移动拷贝构造和移动赋值中直接把资源所有权进行了转移,而非拷贝,这就大大提高了执行效率。

      Stack(int)             // 构造s
      Stack(int)             // 构造tmp
      Stack(Stack&&)         // 调用带右值引用的拷贝构造函数,直接将tmp的资源给临时对象
      ~Stack()               // tmp析构
      operator=(Stack&&)     // 调用带右值引用的赋值运算符重载函数,直接将临时对象资源给s
      ~Stack()               // 临时对象析构
      ~Stack()               // s析构
      
    • 右值引用在可以使重载函数变得更加简洁。右值引用可以适用 const T& 和 T& 形式的参数。

      struct W  
      {  
         W(int&, int&) {}  
      };  
        
      struct X  
      {  
         X(const int&, int&) {}  
      };  
        
      struct Y  
      {  
         Y(int&, const int&) {}  
      };  
        
      struct Z  
      {  
         Z(const int&, const int&) {}  
      };
      
      
      template <typename T, typename A1, typename A2>  
      T* factory(A1& a1, A2& a2)  
      {  
         return new T(a1, a2);  
      } 
      
      
      template <typename T, typename A1, typename A2>  
      T* factory_new(A1&& a1, A2&& a2)  
      {  
         return new T(std::forward<A1>(a1), std::forward<A2>(a2));  
      }  
      
      // demo
      int a = 2;
      int b = 2;
      
      W* c = factory<w>(a, b);	// ok
      Z* d = factory<Z>(2, 2);	// 错误,2 是右值
      
      W* pw = factory_new<W>(a, b);	// ok
      X* px = factory_new<X>(2, b);	// ok
      Y* py = factory_new<Y>(a, 2);	// ok
      Z* e = factory_new<Z>(2, 2);	// ok
      W* f = factory_new<W>(2, 2);	// 错误, 
      

      更多相关内容可以参考:c++——左值、右值、左值引用、右值引用

    第四部分:C++特性

    1. 什么是面向对象(OOP)?面向对象的意义?

    Object Oriented Programming, 面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。其核心思想是数据抽象、继承和动态绑定(多态)。
    面向对象的意义在于:将日常生活中习惯的思维方式引入程序设计中;将需求中的概念直观的映射到解决方案中;以模块为中心构建可复用的软件系统;提高软件产品的可维护性和可扩展性。

    2. 解释下封装、继承和多态?

    • 1). 封装:
      封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。
      封装的意义在于保护或者防止代码(数据)被我们无意中破坏。
    • 2). 继承:
      继承主要实现重用代码,节省开发时间。
      子类可以继承父类的一些东西。
      a. 公有继承(public)
      公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
      b. 私有继承(private)
      私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
      c. 保护继承(protected)
      保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。

    3. 什么时候生成默认构造函数(无参构造函数)?什么时候生成默认拷贝构造函数?什么是深拷贝?什么是浅拷贝?默认拷贝构造函数是哪种拷贝?什么时候用深拷贝?

    • 1). 没有任何构造函数时,编译器会自动生成默认构造函数,也就是无参构造函数;当类没有拷贝构造函数时,会生成默认拷贝构造函数。
    • 2). 深拷贝是指拷贝后对象的逻辑状态相同,而浅拷贝是指拷贝后对象的物理状态相同;默认拷贝构造函数属于浅拷贝。
    • 3). 当系统中有成员指代了系统中的资源时,需要深拷贝。比如指向了动态内存空间,打开了外存中的文件或者使用了系统中的网络接口等。如果不进行深拷贝,比如动态内存空间,可能会出现多次被释放的问题。是否需要定义拷贝构造函数的原则是,是类是否有成员调用了系统资源,如果定义拷贝构造函数,一定是定义深拷贝,否则没有意义。

    4. 构造函数和析构函数的执行顺序?

    构造函数

    • 1). 首先调用父类的构造函数;
    • 2). 调用成员变量的构造函数;
    • 3). 调用类自身的构造函数。

    析构函数

    对于栈对象或者全局对象,调用顺序与构造函数的调用顺序刚好相反,也即后构造的先析构。对于堆对象,析构顺序与delete的顺序相关。

    5. C++的编译环境

    如下图所示,C++的编译环境由如下几部分构成:C++标准库、C语言兼容库、编译器扩展库及编译模块。
    在这里插入图片描述

    #include<iostream>  //C++标准库,不带".h"
    #include<string.h>  //C语言兼容库,由编译器厂商提供
    

    值得注意的是,C语言兼容库功能上跟C++标准库中的C语言子库相同,它的存中主要为了兼容C语言编译器,也就是说如果一个文件只包含C语言兼容库(不包含C++标准库),那么它在C语言编译器中依然可以编译通过。

    6. Most vexing parse

    直接上代码吧。下面 f 和 g 是有问题的,这种情况就称为 Most vexing parse。

    class A {
    public:
    
    	A() { cout << "const without param" << endl; }
    	A(int a) { cout << "const with param" << endl; }
    	A(const A& b) { cout << "copy construct" << endl; }
    };
    
    
    int main(void)
    {
    
    	A a;	// const without param
    	A b(10);	// const with param
    	A c = A();	// const without param
    	A d = A(10);	// const with param
    	A e(d);	// copy construct
    	A f();	
    	A g(A());
    	A h{};	// const without param
    	A i{A{}};	// const without param
    
    	return 0;
    }
    

    问题在哪?

    A f();	// 这个是不是可以看做声明了一个返回值为A的函数,函数名为 f,参数无	
    A g(A());	// 这个是不是可以看做声明了一个返回值为A的函数,函数名为 g, 参数类型为函数指针,这个函数指针的返回值类型为A,参数无
    

    解决办法参考上面的 h, j。

    展开全文
  • 107.spring boot 配置文件有哪几种类型?它们有什么区别? 108.spring boot 有哪些方式可以实现热部署? 109.jpa 和 hibernate 有什么区别? 110.什么是 spring cloud? 111.spring cloud 断路器的作用是什么? 112....
  • 被注解的方法只能一个参数,并且参数类型必须是DownloadTask或UploadTask或DownloadGroupTask 方法名可以为任意字符串 //在这里处理任务执行中的状态,如进度进度条的刷新 @Download.onTaskRunning protected ...
  • C/C++内存有哪几种类型? > C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区...

    整理这篇文章主要是为了自己对C/C++概念的梳理总结。内容来源分布大致为网络、《C++ Primer Plus》和《Effective C++》等。很多大牛已经有很好的总结,参考链接会在文末给出。

    一. 计算机基础

    1. C/C++内存有哪几种类型?

    C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区(new)一说。
    全局变量、static变量会初始化为缺省值,而堆和栈上的变量是随机的,不确定的。

    2. 堆和自由存储区的区别?

    • 总的来说,堆是C语言和操作系统的术语,是操作系统维护的一块动态分配内存;自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。他们并不是完全一样。
    • 从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。

    3. 堆和栈的区别?

    1. 堆存放动态分配的对象——即那些在程序运行时动态分配的对象,比如 new 出来的对象,其生存期由程序控制;
    2. 栈用来保存定义在函数内的非static对象,如局部变量,仅在其定义的程序块运行时才存在;
    3. 静态内存用来保存static对象,类static数据成员以及定义在任何函数外部的变量,static对象在使用之前分配,程序结束时销毁;
    4. 栈和静态内存的对象由编译器自动创建和销毁。

    4. 程序编译的过程?

    程序编译的过程中就是将用户的文本形式的源代码(c/c++)转化成计算机可以直接执行的机器代码的过程。主要经过四个过程:预处理、编译、汇编和链接

    一个hello.c的c语言程序如下。

    #include <stdio.h>
    int main()
    {
        printf("happy new year!\n");
        return 0;
    }
    

    在这里插入图片描述

    5. 计算机内部如何存储负数和浮点数?

    • 负数比较容易,就是通过一个标志位和补码来表示。
    • 对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit,double数据占用64bit,我们在声明一个变量float f= 2.25f的时候,是如何分配内存的呢?如果胡乱分配,那世界岂不是乱套了么,其实不论是float还是double在存储方式上都是遵从IEEE的规范的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。更多可以参考浮点数表示。
    • 无论是单精度还是双精度在存储中都分为三个部分:

    1). 符号位(Sign) : 0代表正,1代表为负
    2). 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
    3). 尾数部分(Mantissa):尾数部分

    单精度float的存储方式如下:
    在这里插入图片描述
    双精度double的存储方式如下:
    在这里插入图片描述

    6. 左值和右值?

    • 不是很严谨的来说,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。
    int a = 1;     //a是一个左值
    int b = 2;     //b是一个左值
    int c = a + b; //+需要右值,所以a和b都转换成右值,并且返回一个右值
    

    7. 什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?你通常采用哪些方法来避免和减少这类错误?

    用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元即为内存泄露。

    1). 使用的时候要记得指针的长度.
    2). malloc的时候得确定在那里free;new的时候记得delete。
    3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.
    4). 动态分配内存的指针最好不要再次赋值.
    5). 在C++中应该优先考虑使用智能指针.

    二. C与C++

    1. C和C++的区别?

    1. C++是C的超集;
    2. C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

    2. int fun() 和 int fun(void)的区别?

    这里考察的是c 中的默认类型机制。

    • 在c中,int fun() 会解读为返回值为int(即使前面没有int,也是如此,但是在c++中如果没有返回类型将报错),输入类型和个数没有限制, 而int fun(void)则限制输入类型为一个void。
    • 在c++下,这两种情况都会解读为返回int类型,输入void类型。

    3. const 有什么用途

    1. 定义只读变量,或者常量(只读变量和常量的区别参考下面一条);
    2. 修饰函数的参数和函数的返回值;
    3. 修饰函数的定义体,这里的函数为类的成员函数,被const修饰的成员函数代表不能修改成员变量的值,因此const成员函数只能调用const成员函数;
    4. 只读对象。只读对象只能调用const成员函数。

    4. 在C中用const 能定义真正意义上的常量吗?C++中的const呢?

    在c中不能。c中的const仅仅是从编译层来限定,不允许对const 变量进行赋值操作,在运行期是无效的,所以并非是真正的常量(比如通过指针对const变量是可以修改值的),但是c++中是有区别的,c++在编译时会把const常量加入符号表,以后(仍然在编译期)遇到这个变量会从符号表中查找,所以在C++中是不可能修改到const变量的

    补充:

    1. c中的局部const常量存储在栈空间,全局const常量存在只读存储区,所以全局const常量也是无法修改的,它是一个只读变量。
    2. 这里需要说明的是,常量并非仅仅是不可修改,而是相对于变量,它的值在编译期已经决定,而不是在运行时决定。
    3. c++中的const 和宏定义是有区别的,宏是在预编译期直接进行文本替换,而const发生在编译期,是可以进行类型检查和作用域检查的。
    4. c语言中只有enum可以实现真正的常量。
    5. c++中只有用字面量初始化的const常量会被加入符号表,而变量初始化的const常量依然只是只读变量。
    6. c++中const成员为只读变量,可以通过指针修改const成员的值,另外const成员变量只能在初始化列表中进行初始化。

    5. 宏和内联(inline)函数的比较?

    1. 首先宏是C中引入的一种预处理功能;
    2. 内联(inline)函数是C++中引用的一个新的关键字;C++中推荐使用内联函数来替代宏代码片段;
    3. 内联函数将函数体直接扩展到调用内联函数的地方,这样减少了参数压栈,跳转,返回等过程;
    4. 由于内联发生在编译阶段,所以内联相较宏,是有参数检查和返回值检查的,因此使用起来更为安全;
    5. 需要注意的是, inline会向编译期提出内联请求,但是是否内联由编译期决定(当然可以通过设置编译器,强制使用内联);
    6. 由于内联是一种优化方式,在某些情况下,即使没有显示的声明内联,比如定义在class内部的方法,编译器也可能将其作为内联函数。
    7. 内联函数不能过于复杂,最初C++限定不能有任何形式的循环,不能有过多的条件判断,不能对函数进行取地址操作等,但是现在的编译器几乎没有什么限制,基本都可以实现内联。

    6. C++中有了malloc / free , 为什么还需要 new / delete?

    1. malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
    2. 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
      由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

    最后补充一点题外话,new 在申请内存的时候就可以初始化(如下代码), 而malloc是不允许的。另外,由于malloc是库函数,需要相应的库支持,因此某些简易的平台可能不支持,但是new就没有这个问题了,因为new是C++语言所自带的运算符。

    7. C和C++中的强制类型转换?

    C中是直接在变量或者表达式前面加上(小括号括起来的)目标类型来进行转换,一招走天下,操作简单,但是由于太过直接,缺少检查,因此容易发生编译检查不到错误,而人工检查又及其难以发现的情况;而C++中引入了下面四种转换:

    1. static_cast
      a. 用于基本类型间的转换
      b. 不能用于基本类型指针间的转换
      c. 用于有继承关系类对象间的转换和类指针间的转换
    2. dynamic_cast
      a. 用于有继承关系的类指针间的转换
      b. 用于有交叉关系的类指针间的转换
      c. 具有类型检查的功能
      d. 需要虚函数的支持
    3. reinterpret_cast
      a. 用于指针间的类型转换
      b. 用于整数和指针间的类型转换
    4. const_cast
      a. 用于去掉变量的const属性
      b. 转换的目标类型必须是指针或者引用

    在C++中,普通类型可以通过类型转换构造函数转换为类类型,那么类可以转换为普通类型吗?答案是肯定的。但是在工程应用中一般不用类型转换函数,因为无法抑制隐式的调用类型转换函数(类型转换构造函数可以通过explicit来抑制其被隐式的调用),而隐式调用经常是bug的来源。实际工程中替代的方式是定义一个普通函数,通过显式的调用来达到类型转换的目的。

    8. static 有什么用途

    1. 静态(局部/全局)变量
    2. 静态函数
    3. 类的静态数据成员
    4. 类的静态成员函数

    9. 类的静态成员变量和静态成员函数各有哪些特性?

    静态成员变量

    1. 静态成员变量需要在类内声明(加static),在类外初始化(不能加static),如下例所示;
    2. 静态成员变量在类外单独分配存储空间,位于全局数据区,因此静态成员变量的生命周期不依赖于类的某个对象,而是所有类的对象共享静态成员变量;
    3. 可以通过对象名直接访问公有静态成员变量;
    4. 可以通过类名直接调用公有静态成员变量,即不需要通过对象,这一点是普通成员变量所不具备的。
    class example{
    private:
    static int m_int; //static成员变量
    };
    
    int example::m_int = 0; //没有static
    
    cout<<example::m_int; //可以直接通过类名调用静态成员变量
    

    静态成员函数

    1. 静态成员函数是类所共享的;
    2. 静态成员函数可以访问静态成员变量,但是不能直接访问普通成员变量(需要通过对象来访问);需要注意的是普通成员函数既可以访问普通成员变量,也可以访问静态成员变量;
    3. 可以通过对象名直接访问公有静态成员函数;
    4. 可以通过类名直接调用公有静态成员函数,即不需要通过对象,这一点是普通成员函数所不具备的。
    class example{
    private:
    static int m_int_s; //static成员变量
    int m_int;
    static int getI() //静态成员函数在普通成员函数前加static即可
    {
      return m_int_s; //如果返回m_int则报错,但是可以return d.m_int是合法的
    }
    };
    
    cout<<example::getI(); //可以直接通过类名调用静态成员变量
    

    10. 在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?

    C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同,假设某个函数原型为:

     void foo(int x, int y);
    

    该函数被C编译器编译后在库中的名字为 _foo, 而C++编译器则会产生像: _foo_int_int 之类的名字。为了解决此类名字匹配的问题,C++提供了C链接交换指定符号 extern “C”。

    11. 头文件中的 ifndef/define/endif 是干什么用的? 该用法和 program once 的区别?

    相同点:

    它们的作用是防止头文件被重复包含。

    不同点:

    1. ifndef 由语言本身提供支持,但是 program once 一般由编译器提供支持,也就是说,有可能出现编译器不支持的情况(主要是比较老的编译器)。
    2. 通常运行速度上 ifndef 一般慢于 program once,特别是在大型项目上, 区别会比较明显,所以越来越多的编译器开始支持 program once。
    3. ifndef 作用于某一段被包含(define 和 endif 之间)的代码, 而 program once 则是针对包含该语句的文件, 这也是为什么 program once 速度更快的原因。
    4. 如果用 ifndef 包含某一段宏定义,当这个宏名字出现“撞车”时,可能会出现这个宏在程序中提示宏未定义的情况(在编写大型程序时特性需要注意,因为有很多程序员在同时写代码)。相反由于program once 针对整个文件, 因此它不存在宏名字“撞车”的情况, 但是如果某个头文件被多次拷贝,program once 无法保证不被多次包含,因为program once 是从物理上判断是不是同一个头文件,而不是从内容上。

    三. 数组、指针 & 引用

    1. 指针和引用的区别?

    相同点:

    1. 都是地址的概念;
    2. 都是“指向”一块内存。指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名;
    3. 引用在内部实现其实是借助指针来实现的,一些场合下引用可以替代指针,比如作为函数形参。

    不同点:

    1. 指针是一个实体,而引用(看起来,这点很重要)仅是个别名;
    2. 引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
    3. 引用不能为空,指针可以为空;
    4. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
    5. 指针和引用的自增(++)运算意义不一样;
    6. 引用是类型安全的,而指针不是 (引用比指针多了类型检查)
    7. 引用具有更好的可读性和实用性。

    2. 引用占用内存空间吗?

    如下代码中对引用取地址,其实是取的引用所对应的内存空间的地址。这个现象让人觉得引用好像并非一个实体。但是引用是占用内存空间的,而且其占用的内存和指针一样,因为引用的内部实现就是通过指针来完成的。

    比如 Type& name; <===> Type* const name。

    int main(void)
    {
            int a = 8;
            const int &b = a;
            int *p = &a;
            *p = 0;
            cout<<a; //output 0
        return 0;
    }
    

    3. 三目运算符

    在C中三目运算符(? :)的结果仅仅可以作为右值,比如如下的做法在C编译器下是会报错的,但是C++中却是可以是通过的。这个进步就是通过引用来实现的,因为下面的三目运算符的返回结果是一个引用,然后对引用进行赋值是允许的。

    int main(void)
    {
            int a = 8;
            int b = 6;
            (a>b ? a : b) = 88;
            cout<<a; //output 88
        return 0;
    }
    

    四. C++特性

    1. 什么是面向对象(OOP)?面向对象的意义?

    • Object Oriented Programming, 面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。其核心思想是数据抽象、继承和动态绑定(多态)
    • 面向对象的意义在于:将日常生活中习惯的思维方式引入程序设计中;将需求中的概念直观的映射到解决方案中;以模块为中心构建可复用的软件系统;提高软件产品的可维护性和可扩展性。

    2. 解释下封装、继承和多态?

    封装:

    • 封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。
    • 封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

    继承:

    继承主要实现重用代码,节省开发时间。子类可以继承父类的一些东西。

    • a. 公有继承(public)
      公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
    • b. 私有继承(private)
      私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
    • c. 保护继承(protected)
      保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。

    多态:

    • 函数的多态又称为函数的重载,函数参数的数目、类型和排列顺序中只要有一项不相同,而且有相同函数名则称之函数的多态。
    • 在类中,多态就是许多情况下可以互换地使用基类型和派生类型的多种形态。依赖于动态绑定机制。
    • C++中默认不使用动态绑定(默认为静态联编,而不是动态联编)。要触发动态绑定必须满足两个条件:
    1. 接口函数的形式参数必须是引用类型或者指针类型
    2. 动态执行函数(对象参数的成员函数而非接口函数)必须是声明为虚成员函数。

    3. 什么时候生成默认构造函数(无参构造函数)?什么时候生成默认拷贝构造函数?什么是深拷贝?什么是浅拷贝?默认拷贝构造函数是哪种拷贝?什么时候用深拷贝?

    1. 没有任何构造函数时,编译器会自动生成默认构造函数,也就是无参构造函数;当类没有拷贝构造函数时,会生成默认拷贝构造函数。
    2. 深拷贝是指拷贝后对象的逻辑状态相同,而浅拷贝是指拷贝后对象的物理状态相同;默认拷贝构造函数属于浅拷贝。
    3. 当系统中有成员指代了系统中的资源时,需要深拷贝。比如指向了动态内存空间,打开了外存中的文件或者使用了系统中的网络接口等。如果不进行深拷贝,比如动态内存空间,可能会出现多次被释放的问题。是否需要定义拷贝构造函数的原则是,是类是否有成员调用了系统资源,如果定义拷贝构造函数,一定是定义深拷贝,否则没有意义。

    4. 构造函数和析构函数的执行顺序?

    构造函数执行顺序

    1). 首先调用父类的构造函数;
    2). 调用成员变量的构造函数;
    3). 调用类自身的构造函数。

    析构函数

    对于栈对象或者全局对象,调用顺序与构造函数的调用顺序刚好相反,也即后构造的先析构。对于堆对象,析构顺序与delete的顺序相关。

    参考:
    https://blog.csdn.net/kuweicai/article/details/82779648#t9

    展开全文
  • o 6.14 说真的, 真机器用非零空指针吗, 或者不同类型用不同的表达? o 6.15 运行时的 ``空指针赋值" 错误是什么意思? * 7. 数组和指针 o 7.1 我在一个源文件中定义了 char a[6], 在另一个中声明了 extern ...
  • 2、常见的服务器分类有哪几种,各自的特点是什么? 服务器主要分为塔式、机架、刀片三种服务器类型 一、塔式服务器 1、塔式服务器是见得最多的一种,其外形及结构都与普通的PC主机相差无几,只是个头稍大,外
  • 在教材中1.2.1节提到这种新型计算机网络必须满足的要求一条是“能够非常可靠地传送数据”。但因特网的网络层使用IP协议,它只能提供不可靠的数据传输。那么这里没有什么矛盾? 问题1-4:在具有五层协议的体系...
  • 引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...
  • Java IO 流分为几种类型? 字节流和字符流的关系与区别? 缓冲流的效率一定高吗? 缓冲流体现了Java 中种设计模式思想? 为什么要实现序列化?如何实现序列化? 序列化数据后,再次修改类文件,读数据会出...
  • C++程序员面试宝典

    热门讨论 2013-04-01 13:36:19
    面试题37 C++中有哪几种基本数据类型 38 面试题38 整型有哪几种形式?各种形式有什么区别 39 面试题39 C++中有哪些常量 40 面试题40 常量与变量有哪些区别 42 4.2 操作符 42 面试题41 操作符有哪些分类 43 面试题42 ...
  • 44. 创建线程池有哪几种方式? 17 45. 线程池都有哪些状态? 18 46. 线程池中 submit()和 execute()方法有什么区别? 18 49. 什么是死锁? 19 50. 怎么防止死锁? 19 51. ThreadLocal 是什么?有哪些使用场景? 20 ...
  • 4.4.6 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。 4.4.7 垃圾回收算法的实现原理。 4.4.8 当出现了内存溢出,你怎么排错。 4.4.9 JVM内存模型的相关知识了解多少,比如重...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    解析XML文档有哪几种方式? 13 39. JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗? 14 40. 一个".java"源文件中是否可以包括多个类(不是内部类)...
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    6.2 显式类型转换 .53 6.3 小 结 .56 第七章 表 达 式 .58 7.1 操 作 符 .58 7.2 算术操作符和算术表达式.59 7.3 赋值操作符和赋值表达式.64 7.4 关系操作符和关系表达式.65 <<page 2>> page begin...
  • C#微软培训资料

    2014-01-22 14:10:17
    6.2 显式类型转换 .53 6.3 小 结 .56 第七章 表 达 式 .58 7.1 操 作 符 .58 7.2 算术操作符和算术表达式.59 7.3 赋值操作符和赋值表达式.64 7.4 关系操作符和关系表达式.65 <<page 2>> page begin...
  • java 面试题 总结

    2009-09-16 08:45:34
    引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...
  • 16.6 决定采用哪种加密技术 670 16.7 小结 671 索引 672 译者序  Oracle Database 11g的推出让关注Oracle的人欣喜万分,不过也不免有些担心,因为此前还没有合适的书系统而深入地介绍这个新版本。要想学习和...
  • 常见网络协议:HTTP、TCP/IP、UDP 网络安全:非对称加密、数字签名、数字证书 网络攻击:DDOS、XSS、CSRF 跨域攻击 怎么学? 计算机网络面试一道非常经典的面试题:说说你从URL输入到最终页面展现的过程。这一题...
  • 方法都可取之处,但我相信,真正的学习应该是“参考+实践”。盲目实践会频繁遇到本来可以避免的陷阱和失败,耽于参考又会成为纸上谈兵,无法得到真才实学。 学习Oracle时,很多书和资料都很参考价值,特别...
  •  如果用户以硬件路由器(或FireWall)为出口上Internet,为实现“通过一台机器监控整个网络”的目的,通常采用下面几种手段:  1.在网关处添加共享式HUB(集线器),Internet出口网络线和监控机网络线均接入HUB。  ...
  • 大话数据结构

    2019-01-10 16:35:22
    于是商品房就出现了各种各样的户型,有几百平米的别墅,也仅两平米的胶囊公寓…… 1.6.1数据类型 11 .1.6.2抽象数据类型 12 1.7总结回顾 14 1.8结尾语 15 最终的结果一定是,你对着别人很牛的说“数据结构——就...
  • 大话数据结构 程杰

    2018-09-01 10:06:43
    于是商品房就出现了各种各样的户型,有几百平米的别墅,也仅两平米的胶囊公寓…… 1.6.1数据类型 11 .1.6.2抽象数据类型 12 1.7总结回顾 14 1.8结尾语 15 最终的结果一定是,你对着别人很牛的说“数据结构——就...
  • 于是商品房就出现了各种各样的户型,有几百平米的别墅,也仅两平米的胶囊公寓…… 1.6.1数据类型 11 .1.6.2抽象数据类型 12 1.7总结回顾 14 1.8结尾语 15 最终的结果一定是,你对着别人很牛的说“数据结构——就...
  • 反正也是要让相邻元素间留足够余地,那干脆所有元素都不要考虑相邻位置了,哪有空位就到哪里。而只是让每个元素知道它下一个元素的位置在哪里。 3.6.1顺序存储结构不足的解决 办法 55 3.6.2线性表链式存储结构定义...
  • 于是商品房就出现了各种各样的户型,有几百平米的别墅,也仅两平米的胶囊公寓…… 1.6.1 数据类型 11 1.6.2 抽象数据类型 12 1.7 总结回顾 14 1.8 结尾语 15 最终的结果一定是,你对着别人很牛的说"数据结构--就...
  • 让写的常见程序:数据结构书上的程序,经典 C 程序(strcmp、strcpy、atoi……) ,C++程序(表现 C++经典特性的) 。第 一次在面试官眼皮底下在纸上写程序,思路容易紊乱。建议大家事先多 练习,找个同学坐在边上...

空空如也

空空如也

1 2 3
收藏数 57
精华内容 22
关键字:

常见网络有哪几种类型