• C++基础知识


    一、C++占用内存分配

    1)、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其

    操作方式类似于数据结构中的栈。

    2)、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回

    收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。

    3)、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的

    全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另

    一块区域。 - 程序结束后由系统释放。

    4)、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放

    5)、程序代码区—存放函数体的二进制代码。

    二、友元函数与友元类

    2 .1为什么使用友元函数

    在实现类之间数据共享时,减少系统开销,提高效率。

    实际上具体大概有下面两种情况需要使用友元函数:

    (1)运算符重载的某些场合需要使用友元。

    (2)两个类要共享数据的时候。

    2.2 参数

    友元函数没有this指针,则参数要有三种情况:

    (1)要访问非static成员时,需要对象做参数

    (2)要访问static成员或全局变量时,则不需要对象做参数

    (3)如果做参数的对象是全局对象,则不需要对象做参数

    2.3 调用

    可以直接调用友元函数,不需要通过对象或指针

    2.4 分类

    (1)普通的友元函数:使普通函数能够访问类。

    语法:声明:friend + 普通函数声明;实现位置:可以在类外或类中;

    实现代码:与普通函数相同;调用:类似普通函数,直接调用

    (2)类Y的所有成员函数都为类X友元函数—友元类:使用单个声明使Y类的所有函数成为类X的友元,它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能

    语法:声明位置:公有私有均可,常写为私有(把类看成一个变量)

    声明: friend + 类名(不是对象哦)

    (3)类Y的一个成员函数为类X的友元函数:使类Y的一个成员函数成为类X的友元,具体而言:在类Y的这个成员函数中,借助参数X,可以直接以X的私有变量

    语法:声明位置:声明在公有中 (本身为函数);声明:friend + 成员函数的声明

    调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制

    2.5 友元函数和类的成员函数的区别

    (1)成员函数有this指针,而友元函数没有this指针

    (2)友元函数是不能被继承的,就像父亲的朋友未必是儿子的朋友

    三、构造函数和析构函数

    3.1 特点

    无论是用户自定义的构造函数还是默认构造函数都主要有以下特点:①. 在对象被创建时自动执行;②. 构造函数的函数名与类名相同;③. 没有返回值类型、也没有返回值;④. 构造函数不能被显式调用。

    3.2 初始化表达式

    使用初始化表进行初始化是在构造函数被调用以前就完成的。每个成员在初始化表中只能出现一次, 并且初始化的顺序不是取决于数据成员在初始化表中出现的顺序, 而是取决于在类中声明的顺序。

    3.3 复制构造函数

    当函数的参数采用按值传递时,编辑器会调用该类的复制构造函数来复制实际参数到被调用函数。

    复制构造函数与类的其他构造函数一样,以类名作为函数的名称,但是其参数只有一个,即该类的常量引用类型。

    3.4 析构函数

    析构函数是在对象被撤销时被自动调用。

    析构函数函数名与类名相同, 紧贴在名称前面用波浪号 ~ 与构造函数进行区分, 例如: ~Point(); 析构函数没有返回类型, 也不能指定参数, 因此析构函数只能有一个, 不能被重载;与构造函数不同的是, 析构函数可以被显式的调用, 以释放对象中动态申请的内存。

    3.5

    当用户没有显式定义析构函数时, 编译器同样会为对象生成一个默认的析构函数, 但默认生成的析构函数只能释放类的普通数据成员所占用的空间, 无法释放通过 new 或 malloc 进行申请的空间, 因此有时我们需要自己显式的定义析构函数对这些申请的空间进行释放, 避免造成内存泄露。

    有关异常:

    (1)不建议在构造函数中抛出异常。

    (2)构造函数抛出异常时,析构函数将不会自动执行,需要手动释放去释放内存。

    (3)析构不应该抛出异常。

    四、拷贝构造函数和重载赋值运算符函数

    4.1 拷贝构造函数

    调用时机:

    (1)当用类的一个对象初始化该类的另一个对象时

    (2)如果函数的形参是类的对象,调用函数时,进行形参和实参的结合时

    (3)如果函数的返回值是类的对象,函数执行完成返回调用者时

    (4)需要产生一个临时类对象时

    4.2 区分拷贝构造函数和重载赋值运算符函数

    Myclass obi1;

    Myclass obj3=obj1; //调用拷贝构造函数

     

    Myclass obj3;

    obj3=obj1; //调用重载赋值运算符函数

    五、this指针

    4.1 概念

    this指针是一个隐含于每一个成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。

    4.2 特点

    (1)this只能在成员函数中使用。全局函数、静态函数都不能使用this.

    实际上,成员函数默认第一个参数为T * const this。

    (2)this在成员函数的开始前构造,在成员函数的结束后清除

     

    在C++中,类和结构是只有一个区别的:类的成员默认是private,而结构是public。 this是类的指针,如果换成结构,那this就是结构的指针了。

    4.3 以下场景需显示的调用this指针

    (1) 为实现对象的链式引用;

    (2) 为避免对同一对象进行赋值操作;

    (3) 在实现一些数据结构时,如list;

    五、继承与派生

    5.1 继承

    类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。

    5.2 派生类

    1)一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承。直接派生,间接派生。

    2)继承方式规定了如何访问基类继承的成员。继承方式有public, private, protected。如果不显示给出继承方式,默认为private继承。

    3)派生类继承基类中除构造和析构函数以外的所有成员。

    基类成员在基类中访问属性

    基类成员在派生类中访问属性

     

    Public

    Private

    Protected

    Public

    Public

    Private

    Protected

    Private

    不可直接访问

    不可直接访问

    不可直接访问

    Protected

    Protected

    Private

    Protected

    5.3 派生类的构造函数和析构函数

    派生类中由基类继承而来的成员的初始化由基类的构造函数完成,派生类中新增成员在派生类的构造函数中初始化。

    构造函数语法

    派生类名::派生类名(参数总表):基类名1(参数表1),基类名(参数名2)....基类名n(参数名n),内嵌子对象1(参数表1),内嵌子对象2(参数表2)....内嵌子对象n(参数表n)

    注:

    构造函数的初始化顺序并不以上面的顺序进行,而是根据声明的顺序初始化。

    析构函数的执行顺序与构造函数相反

    5.4 虚基类

    为了解决多重拷贝的问题,可以将共同基类设置为虚基类

    一般而言,派生类只对其直接基类的构造函数传递参数,但是在虚基类中,不管是直接或间接虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化。

    5.5 赋值兼容原则

    1)、赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。

    2)、赋值兼容规则中所指的替代包括:

    派生类的对象可以赋值给基类对象;

    派生类的对象可以初始化基类的引用;

    派生类对象的地址可以赋给指向基类的指针。

    在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。

    5.6 访问类的私有成员变量的方法

    1)set/get接口

    2)友元类

    3)友元函数

    七、面向对象设计的基本原则

    (1)单一职责原则(Single-Resposibility Principle):一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。 (2)开放封闭原则(Open-Closed principle):软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放(味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况),对修改封闭的(意味着类一旦设计完成,就可以独立其工作,而不要对类尽任何修改)。

    (3)Liskov替换原则(Liskov-Substituion Principle)即里氏替换原则:子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。

    (4)依赖倒置原则(Dependecy-Inversion Principle):依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。

    (5)接口隔离原则(Interface-Segregation Principle):使用多个小的专门的接口,而不要使用一个大的总接口

    (6)迪米特法则又叫最少知识原则(Least Knowledge Principle LKP):就是说一个对象应当对其他对象有尽可能少的了解,

    不和陌生人说话。

    (7)组合/聚集复用原则:尽量使用合成/聚合,而不是使用继承。

  • 相关阅读:
    单元测试之NUnit
    “Oracle.DataAccess.Client.OracleConnection”的类型初始值设定项引发异常
    功能强大的树状结构TreeGrid
    右键效果图
    可视化定义工作流(正在努力做......w)
    关于自动发送邮件换行等问题解决
    清空Cache
    .net发生类型为 System.OutOfMemoryException 的异常解决办法
    再谈xml
    Delphi日期函数大全
  • 原文地址:https://www.cnblogs.com/sunshine1218/p/9058087.html
Copyright © 2020-2023  润新知