c++入门笔记(一)

  • 内存申请、释放

C++ 新增两个关键字,new 和 delete:new 用来动态分配内存,delete 用来释放内存

  1. int *p = new int;  //分配1个int型的内存空间
  2. delete p;  //释放内存

malloc() 一样,new 也是在堆区分配内存,必须手动释放,否则只能等到程序运行结束由操作系统回收。为了避免内存泄露,通常 new 和 deletenew[] 和 delete[] 操作符应该成对出现。

 

  • 函数调用

一个 c++ 程序的执行过程可以认为是多个函数之间的相互调用过程,它们形成了一个或简单或复杂的调用链条,这个链条的起点是 main(),终点也是 main()。当 main() 调用完了所有的函数,它会返回一个值(例如return 0;)来结束自己的生命,从而结束整个程序。

 

  • 内联函数

函数调用是有时间和空间开销的。

内联函数(在函数定义处增加inline关键字):

  • 优点:可以消除函数调用的时空开销。这样当编译器遇到函数调用时,就会用函数的代码替换调用,同时用实参代替形参。
  • 缺点:编译后的程序会存在多分相同的函数拷贝,如果被声明为内联函数的函数体非常大,那么编译后的程序体积也将会变得很大。

当函数比较复杂时,函数调用的时空开销可以忽略,大部分的CPU时间都会花费在执行函数体代码上,所以我们一般是将非常短小的函数声明为内联函数。

 

  • 默认参数

C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。

 

  • 函数重载

定义:重载就是在一个作用范围内(同一个类、同一个命名空间等)有多个名称相同但参数不同的函数。重载的结果是让一个函数名拥有了多种用途,使得命名更加方便(在中大型项目中,给变量、函数、类起名字是一件让人苦恼的问题),调用更加灵活。

函数列表:又叫做函数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同

函数的重载的规则:

  • 函数名称必须相同
  • 参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)
  • 函数的返回类型可以相同也可以不相同
  • 仅仅返回类型不同不足以成为函数的重载

c++是如何做到函数重载的:C++代码在编译时会根据参数列表对函数进行重命名。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错。(这叫做-重载协议)

 

  • -对象

定义:类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化。每个对象都是类的一个具体实例(instance),拥有类的成员变量和成员函数。注意在类定义的最后有一个分号;,它是类定义的一部分,表示类定义结束了,不能省略。

&:获取它的地址

:使用new在堆上创建出来的对象是匿名的,必须要用一个指针指向它。堆内存由程序员管理,对象使用完毕后可以通过delete删除。引用用->

:在栈上创建出来的对象都有一个名字,使用指针不是必须的,形式和定义普通变量类似。栈内存是程序自动管理的,不能使用delete删除在栈上创建的对象。引用用.

 

  • -成员函数-类外定义

当成员函数定义在类外时,就必须在函数名前面加上类名予以限定。::被称为域解析符(也称作用域运算符或作用域限定符),用来连接类名和函数名指明当前函数属于哪个类

成员函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前

 

  • 构造函数

定义:一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显示调用。而是在创建对象时自动执行

特性:

  • 一个类可以有多个重载的构造函数,创建对象时根据传递的实参来判断调用哪一个构造函数;创建对象时提供的实参必须和其中的一个构造函数匹配;反过来说,创建对象时只有一个构造函数会被调用。
  • 构造函数的调用是强制性的,一旦在类中定义了构造函数,那么创建对象时就一定要调用,不调用是错误的。
  • 如果用户自己没有定义构造函数,那么编译器会自动生成一个默认的构造函数,只是这个构造函数的函数体是空的,也没有形参,也不执行任何操作。
  • 默认构造函数的目的是帮助编译器做初始化工作,而不是帮助程序员。这是C++的内部实现机制。

 

  • 析构函数

定义:创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作,例如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。

特点:

  • 析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要程序员显式调用(程序员也没法显式调用),而是在销毁对象时自动执行。构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个~符号。
  • 析构函数没有参数,不能被重载,因此一个类只能有一个析构函数。如果用户没有定义,编译器会自动生成一个默认的析构函数。

 

  • this指针

this 是一个指针,要用->来访问成员变量或成员函数

this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。

几点注意:

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

 

  •  const

常成员函数需要在声明和定义的时候在函数头部的结尾加上 const 关键字。需要强调的是,必须在成员函数的声明和定义处同时加 const 关键字。

区分一下 const 的位置:

  • 函数开头的 const 用来修饰函数的返回值,表示返回值是 const 类型,也就是不能被修改,例如const char * getname()。
  • 函数头部的结尾加上 const 表示常成员函数,这种函数只能读取成员变量的值,而不能修改成员变量的值,例如char * getname() const。

  

  • C++中的 struct 和 class 基本是通用的,唯有几个细节不同

  • 使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的。
  • class 继承默认是 private 继承,而 struct 继承默认是 public 继承。
  • class 可以使用模板,而 struct 不能。

在编写C++代码时,强烈建议使用 class 来定义类,而使用 struct 来定义结构体,这样做语义更加明确。

 

  • 在不给字符串赋值时,字符串的默认值是:””(空字符串

  

  • c++中单引号、双引号的区别

  1. 类型不同:单引号表示类型为字符类型双引号表示类型为字符串类型
  2. 数据长度不同:单引号的数据长度固定,因为只有一个字符,所以数据长度为1;双引号的数据长度不固定,由字符串的字符数量决定
  3. 尾部不同:单引号只有一个字符,不会在字符尾部添加’\0’结尾;双引号,系统会将双引号里的字符串内容的尾部自动添加’\0’结尾

 

  • 参数传递

参数的传递本质上是一次赋值的过程,赋值就是对内存进行拷贝。所谓内存拷贝,是指将一块内存上的数据复制到另一块内存上。

 

  • 引用

引用在定义时需要添加&,在使用时不能添加&。使用时添加&表示取地址。

 

  • 继承

sample:class Student: public People

多继承:

在多继承中,如果几个基类中有相同的成员变量,编译器就会产生歧义。为了消除歧义,可以在引用的前面指明它具体来自哪个类(::)

为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上 virtual 关键字就是虚继承。

  

  • 重写、重载、重定义 

重写=覆盖=override

是指派生类函数重写(覆盖)基类函数

  1. 不同的范围,分别位于基类和派生类中
  2. 函数的名字相同
  3. 参数相同(必须有相同的类型、名称、参数列表)
  4. 基类函数必须有virtual关键字(被重写的函数不能是static的

 

重载=overload

成员函数

  1. 相同的范围(在同一个类中,实现若干重载的方法)
  2. 函数的名字相同
  3. 形参列表不同
  4. virtual关键字可有可无

 

重定义

派生类对基类的成员函数重新定义,即派生类定义了某个函数,该函数的名字与基类中函数名字一样。

  重定义也叫做隐藏,子类重定义父类中有相同名称的非虚函数(参数可以不同)。如果一个类,存在和父类相同的函数,那么这个类将会覆盖其父类的方法,除非你在调用的时候,强制转换为父类类型,否则试图对子类和父类做类似重载的调用时不能成功的。

重定义需要注意:

  1. 不在同一个作用域(分别位于基类、派生类)
  2. 函数的名字必须相同
  3. 对函数的返回值、形参列表无要求
  4. 若派生类定义该函数与基类的成员函数完全一样(返回值、形参列表均相同),且基类的该函数为virtual,则属于派生类重写基类的虚函数
  5. 若重新定义了基类中的一个重载函数,则在派生类中,基类中该名字函数(即其他所有重载版本)都会被自动隐藏,包括同名的虚函数

 

  • 派生类屏蔽了与其同名的基类函数
  • 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏
  • 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有关键字,此时,基类的函数被隐藏

 

  • 多态

多态的概念比较复杂,一种不严谨的说法是:继承是子类使用父类的方法,而多态是父类使用子类的方法。

 

posted @ 2020-07-22 09:29  小嘉欣  阅读(175)  评论(0编辑  收藏  举报