• c++基本知识


    new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。

    C++ this指针详解

    this指针几点注意:
    this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。
    this 只能在成员函数内部使用,用在其他地方没有意义,也是非法的。
    只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用(后续会讲到 static 成员)。

    C++ static静态成员变量

    static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只分配一份内存,所有对象使用的都是这份内存中的数据。当某个对象修改了 static 成员变量,也会影响到其他对象。

    static 成员变量必须在类声明的外部初始化
    静态成员变量在初始化时不能再加 static,但必须要有数据类型。被 private、protected、public 修饰的静态成员变量都可以用这种方式初始化。
    static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。
    static 成员变量既可以通过对象来访问,也可以通过类来访问
    static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问

    1) 一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。

    2) static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。

    3) 静态成员变量必须初始化,而且只能在类体外进行。例如:
    int Student::m_total = 10;
    初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为 0。全局数据区的变量都有默认的初始值 0,而动态数据区(堆区、栈区)变量的默认值是不确定的,一般认为是垃圾值。

    4) 静态成员变量既可以通过对象名访问,也可以通过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。当通过对象名访问时,对于不同的对象,访问的是同一份内存。

    C++ static静态成员函数

    静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
    在C++中,静态成员函数的主要目的是访问静态成员。
    和静态成员变量类似,静态成员函数在声明时要加 static,在定义时不能加 static。静态成员函数可以通过类来调用(一般都是这样做),也可以通过对象来调用

    C++类与const关键字

    const 成员变量的用法和普通 const 变量的用法相似,只需要在声明时加上 const 关键字。初始化 const 成员变量只有一种方法,就是通过参数初始化表
    const 成员函数可以使用类中的所有成员变量,但是不能修改它们的值,这种措施主要还是为了保护数据而设置的。
    const 成员函数也称为常成员函数。
    需要注意的是,必须在成员函数的声明和定义处同时加上 const 关键字。
    一旦将对象定义为常对象之后,不管是哪种形式,该对象就只能访问被 const 修饰的成员了(包括 const 成员变量和 const 成员函数),因为非 const 成员可能会修改对象的数据(编译器也会这样假设),C++禁止这样做。

    C++ friend友元函数和友元类

    友元函数不同于类的成员函数,在友元函数中不能直接访问类的成员,必须要借助对象。
    这里简单介绍一下类的提前声明。一般情况下,类必须在正式声明之后才能使用;但是某些情况下(如上例所示),只要做好提前声明,也可以先使用。

    但是应当注意,类的提前声明的使用范围是有限的,只有在正式声明一个类以后才能用它去创建对象。
    关于友元,有两点需要说明:
    友元的关系是单向的而不是双向的。如果声明了类 B 是类 A 的友元类,不等于类 A 是类 B 的友元类,类 A 中的成员函数不能访问类 B 中的 private 成员。
    友元的关系不能传递。如果类 B 是类 A 的友元类,类 C 是类 B 的友元类,不等于类 C 是类 A 的友元类。

    除非有必要,一般不建议把整个类声明为友元类,而只将某些成员函数声明为友元函数,这样更安全一些。

    C++ class和struct的区别

    在C语言中,struct 只能包含成员变量,不能包含成员函数。而在C++中,struct 类似于 class,既可以包含成员变量,又可以包含成员函数。

    C++中的 struct 和 class 基本是通用的,唯有几个细节不同:
    使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的。
    class 继承默认是 private 继承,而 struct 继承默认是 public 继承。
    class 可以使用模板,而 struct 不能。

    C++引用的概念与基本使用

    引用(Reference)是 C++ 相对于C语言的又一个扩充。引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。引用类似于 Windows 中的快捷方式,一个可执行程序可以有多个快捷方式,通过这些快捷方式和可执行程序本身都能够运行程序;引用还类似于人的绰号(笔名),使用绰号(笔名)和本名都能表示一个人。

    引用的定义方式类似于指针,只是用&取代了*,语法格式为:
    type &name = data;
    type 是被引用的数据的类型,name 是引用的名称,data 是被引用的数据。引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它数据,这有点类似于常量(const 变量)。
    如果不希望通过引用来修改原始的数据,那么可以在定义时添加 const 限制,形式为:
    const type &name = value;
    也可以是:
    type const &name = value;
    这种引用方式为常引用
    在将引用作为函数返回值时应该注意一个小问题,就是不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用,因为当函数调用完成后局部数据就会被销毁,有可能在下次使用时数据就不存在了,C++ 编译器检测到该行为时也会给出警告。

    C++ typeid运算符

    C++运算符重载的概念和语法

    所谓重载,就是赋予新的含义。函数重载(Function Overloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作。运算符重载(Operator Overloading)也是一个道理,同一个运算符可以有不同的功能。

    运算符重载其实就是定义一个函数,在函数体内实现想要的功能,当用到该运算符时,编译器会自动调用这个函数。也就是说,运算符重载是通过函数实现的,它本质上是函数重载。
    operator是关键字,专门用于定义重载运算符的函数。我们可以将operator 运算符名称这一部分看做函数名。
    运算符重载函数除了函数名有特定的格式,其它地方和普通函数并没有区别。
    运算符重载函数不仅可以作为类的成员函数,还可以作为全局函数。

    C++运算符重载的规则

    1) 并不是所有的运算符都可以重载。能够重载的运算符包括:
    +  -  *  /  %  ^  &  |  ~  !  =  <  >  +=  -=  *=  /=  %=  ^=  &=  |=  <<  >>  <<=  >>=  ==  !=  <=  >=  &&  ||  ++  --  ,  ->*  ->  ()  []  new  new[]  delete  delete[]
    2) 重载不能改变运算符的优先级和结合性。
    3) 重载不会改变运算符的用法,原有有几个操作数、操作数在左边还是在右边,这些都不会改变。例如~号右边只有一个操作数,+号总是出现在两个操作数之间,重载后也必须如此。

    4) 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。

    5) 运算符重载函数既可以作为类的成员函数,也可以作为全局函数。

    将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。
    3) 重载不会改变运算符的用法,原有有几个操作数、操作数在左边还是在右边,这些都不会改变。例如~号右边只有一个操作数,+号总是出现在两个操作数之间,重载后也必须如此。

    4) 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。

    5) 运算符重载函数既可以作为类的成员函数,也可以作为全局函数。

    将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。
    6) 箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载。

    C++函数模板(Function Template)

    在C++中,数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当发生函数调用时,编译器可以根据传入的实参自动推断数据类型。这就是类型的参数化。

    值(Value)和类型(Type)是数据的两个主要特征,它们在C++中都可以被参数化。

    所谓函数模板,实际上是建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板(Function Template)。

    在函数模板中,数据的值和类型都被参数化了,发生函数调用时编译器会根据传入的实参来推演形参的值和类型。换个角度说,函数模板除了支持值的参数化,还支持类型的参数化。

    一但定义了函数模板,就可以将类型参数用于函数定义和函数声明了。说得直白一点,原来使用 int、float、char 等内置类型的地方,都可以用类型参数来代替。

    template <typename 类型参数1 , typename 类型参数2 , ...> 返回值类型  函数名(形参列表){
        //在函数体中可以使用类型参数
    }
    类型参数可以有多个,它们之间以逗号,分隔。类型参数列表以< >包围,形式参数列表以( )包围。

    typename关键字也可以使用class关键字替代,它们没有任何区别。C++ 早期对模板的支持并不严谨,没有引入新的关键字,而是用 class 来指明类型参数,但是 class 关键字本来已经用在类的定义中了,这样做显得不太友好,所以后来 C++ 又引入了一个新的关键字 typename,专门用来定义类型参数。不过至今仍然有很多代码在使用 class 关键字,包括 C++ 标准库、一些开源程序等。
    函数模板也可以提前声明,不过声明时需要带上模板头,并且模板头和函数定义(声明)是一个不可分割的整体,它们可以换行,但中间不能有分号。

    C++类模板(Class Template)

    类模板和函数模板都是以 template 开头(当然也可以使用 class,目前来讲它们没有任何区别),后跟类型参数;类型参数不能为空,多个类型参数用逗号隔开。
    一但声明了类模板,就可以将类型参数用于类的成员函数和成员变量了。换句话说,原来使用 int、float、char 等内置类型的地方,都可以用类型参数来代替。
    注意:模板头和类头是一个整体,可以换行,但是中间不能有分号。
    在类外定义成员函数时仍然需要带上模板头,格式为:
    template<typename 类型参数1 , typename 类型参数2 , …>
    返回值类型 类名<类型参数1 , 类型参数2, ...>::函数名(形参列表){
        //TODO:
    }
    第一行是模板头,第二行是函数头,它们可以合并到一行,不过为了让代码格式更加清晰,一般是将它们分成两行。
    除了 template 关键字后面要指明类型参数,类名 后面也要带上类型参数,只是不加 typename 关键字了。另外需要注意的是,在类外定义成员函数时,template 后面的类型参数要和类声明时的一致。

  • 相关阅读:
    Go语言的流程控制(条件,选择,控制,跳转,闭包)
    Go语言的map
    数据库-关系模型
    数据库的格式化模型(层次模型和网状模型)
    数据库-数据模型
    操作系统的功能与定义
    操作系统功能和定义
    操作系统应用程序
    密码学概论
    JAVA多线程提高四:多个线程之间共享数据的方式
  • 原文地址:https://www.cnblogs.com/Malphite/p/10887567.html
Copyright © 2020-2023  润新知