c++学习笔记

最近又找了老师聊了一下未来的方向,然后就是又改变了。网络分析不让我继续做了,继续c++。苦逼,都快忘完了,这一次是写成随笔形式,便于下次重新复习。参考用书:c++ primer plus

 

一、c++简介

什么是程序?

程序=算法+数据

我们都知道c++是面向对象编程的一门语言。其实这不够具体。c++也能够进行结构化编程和泛型编程。首先解释一下这三种模式。

1.结构化编程

  这是C语言的特性,但由于c++在C语言的基础上开发出来的,所以也支持这种模式。提出结构化编程,是由于旧式程序的执行顺序很混乱,这样是不利于阅读和理解。结构化编程就可以很好的理解,这主要基于结构化编程的两种特性。

  1.将分支限制为一组行为良好的结构。(for  循环。while循环)

  2.自顶向下的设计思想。结构化编程技术反映了过程性的编程思想。根据执行的操作来构思一个程序。

  *结构化编程是更注重于从算法的角度来组织程序

2.面向对象编程

  这是c++语言的特性。与结构化编程不同,oop编程更注重的是数据。oop不像过程性编程那样,试图使问题满足于语言的过程性方法,oop是试图让语言来满足问题的要求。其理念是设计与问题本质相对应的数据格式。类就应运而出。在c++中类是一种规范,它描述了这种新型的数据格式,对象是根据这种规范构造的特定的数据结构。oop程序首先是设计类,这些类准确的描述了程序要处理的东西。从低级(类)到高级(程序)的处理过程叫做自下向上编程。

oop特性:

  1.封装2.继承3.多态4.抽象。

这些特性在类中理解更好。

3.泛型编程

它与oop目标相同,即重用代码和抽象通用。但它更强调的是独立于特定的数据类型。c++模板提供了完成这种任务的机制。

 

二、进入c++

  1.变量和常量。

    变量是程序员自己在程序中编写的值,常量是字面量,直观的表示出来的值。

int a;//这是一个整型变量,你只知道这是一个整型的值,而不知道具体数值。
100 //这是一个字面量,是常量,可以对变量赋值,能显示的表示为多少。但计算机赋值时,根据你要赋值的
    //赋值的变量来进行存储。如果不指定,能存储的最小类型来存储。

 

  C++的基本数据类型。

    其实这几种类型并不是像以前教科书上,简单的归纳为每个特定的类型,占据几个字节。而要从计算机的内存角度来考量。首先是内存是用位来存储数据的。字节是内存的度量单位。

  1.C++不同的整型使用不同的内存量来存储整数。头文件(climits)中可以具体查询到。(内存量的多少直接决定了这种类型最大能存放的数据的大小)

    整型:Short,int,long,long long.(unsigned)

    整型字面量:具体的数字,有不同的写法。代表了不同的整型。(l.u.)

    符号常量:const。变量和字面量绑定。

 

  2.浮点型:float.double.long double(精度)。可以表示很大的数,也可以表示很小的数。浮点型常量可以用科学记数法来进行表示。浮点型实际存储时以2的几次方来进行存储。

 

 

  3.字符型:char。

 

  **浮点数需要考虑的是精度问题。精度很重要。小数的存储方式很特别。用科学记数法来表示的。要理解。精度的问题,和存储方式有关,存储方式为一个数,一个幂分开存储。这个数就代表了精度。

   **字符型。把这个和整型一起理解。和编码集相关。

三种编码格式(准备知识)

所有的string类都是以C-style字符串为基础的。C-style字符串是字符数组。字符类型有三种编码格式:

l  第一种是单字节字符集(singlebyte character set or SBCS)。

在这种编码格式下,所有字符都只用一个字节表示,ASCII码就是单字节字符。用"0"来表示一个字节的结束。

l   第二种编码格式是多字节字符集(multi-bytecharacter set or MBCS)。

即:支持多字节的字符集。

多字节字符集 (MBCS) 是一种旧的方式以支持无法用单字节表示的字符集(如日文和中文)的方法。 如果执行新开发,对于所有的文本字符串应该使用Unicode,除非最终用户没有看到系统字符串。 MBCS 是传统技术,不建议用于新开发中。

 

最常见的 MBCS 实现是双字节字符集(DBCS)。在Windows里的MBCS包含两种字符类型:单字节字符(singlebyte characters )和双字节字符(doublebyte characters)。

由于Windows 里使用的多字节字符绝大部分是两个字节长,MBCS常被DBCS(double-byte character set)代替。

 一般来说,VisualC++(尤其是 MFC)完全支持 DBCS。

 

 

l  第三种编码格式是Unicode。

最初的unicode编码是固定长度的,16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符。显然,这样要表示各种语言中所有的字符是远远不够的。Unicode4.0规范考虑到了这种情况,定义了一组附加字符编码,附加字符编码采用2个16位来表示,这样最多可以定义1048576个附加字符,目前unicode4.0只定义了45960个附加字符。

Unicode只是一个编码规范,目前实际实现的unicode编码只有三种:UTF-8,UCS-2和UTF-16,三种unicode字符集之间可以按照规范进行转换。

 

3. MBCS编码,Unicode编码与ACIll编码对比

 

Unicode编码:

有三种编码方式

MBCS编码:

多字节编码。

ACILL编码:

单字节编码。

 

 

 

 

    类型转换: 

     类型转换的一个原则就是:宽度宽的不能向宽度窄的数据类型转换。类型转换经常用到的地方:算数运算符,函数传参,赋值语句。

     强制类型转换为:(type)var

    复合类型:数组、字符串、结构体、枚举、共同体。

    1.数组

     数组的声明:

数组。

数组的声明很重要。

初始化,

索引

取值和赋值。

 

字符串

字符数组,字符串常量,string

 

字符数组可以表示字符串,但并不是每一个字符数组都是字符串。最后一个是不是空字符‘\0’

 

字符串常量可以为字符数组赋值。字符串常量用双引号表示。后面会有隐藏的空字符。这是c-style的原因。

 

String是新添加的一个类。用法非常灵活。可以用字符串常量来赋值。字符数组不可以直接给字符串赋值,两者类型完全不同。

 

关于输入字符串的问题:cin有个成员函数来处理。

Cin.get()

Cin.getline()

两者的区别在于是否保留换行符。可以继续添加理解。

 

字符数组的函数,拼接,比较。

String就比较直白,可以直接运算。

计算长度方法也有不同。Strlen() 和str.size()

 

结构体。

关键字  struct

成员运算符(.)

用逗号隔开

 

初始化,和数组差不多。

 

外部声明

 

用结构体占位。冒号表示

  C语言中的结构体和c++中的结构体是有一点不同的。必须用typedef。

       https://www.cnblogs.com/qiumingcheng/p/7814970.html

 

 

函数

 

l  定义

l  原型

l  调用

定义:有无返回值,分为两种,一,void二,除数组外的其他类型。

原型:与编译器的接口。告诉编译器怎么做。

调用:形参para,实参argu。通常是按值传递,即传递一个副本。

 

 

数组和函数。

 

在函数传递数组的格式通常是这样的

 

Int  sun(int  arr[],int n)

如果不要修改,需要添加const

 

数组参数,本质上也是按值传递的。

 

函数与二维数组。

 

Int  f(int  a[][size],int n)

 

Size是必须的。这样可以很清楚的表达出意思。

 

函数与字符串。

 

F(char []),不用标识数组长度,字符串最后会有空值。

 

函数与string

 

F(string  n)与其他基本类型差不多。

 

函数与结构体

 

与其他类型差不多。

 

函数与array对象。

 

函数指针。。。

声明函数指针为:type (*pf)(pram)  double (*pf)(int)

 **在这里书中有个特别强调的地方:const 和指针。int * const pt  and   const int * pt的区别。

第一个是pt(指针)不能修改。

第二个是指针指向的数据不能修改。还有重要的一点,用const声明的常量不能用非const的指针来指向。

内联函数:

  使用相应的函数代码替换函数调用。在函数声明前加上inline。在函数定义前加上加上inline。

引用变量:已定义变量的别名。

    1.创建引用变量。

int a;
int & b=a;

  需要注意的几点:声明引用时必须初始化。这也就意味着,一旦与某个变量关联起来,就一直效忠于这个变量。

  2.将引用作为函数参数。

    这是C++ 对C的超越。因为C语言只能按值传递。

    引用形式

void a(int & a ,int &b)

    这里需要注意的是:函数调用时,实参不要是表达式。否则会出现问题。

    返回引用时,要注意:要避免返回一个局部变量的引用。

int & f(int & b){return b;}

 

  3.将引用用于结构

    引用非常适用于结构和类。设计引用的目的就是为了用于这些类型。

struct a{};
void f(a & t){};//可以修改
void f(const a & t)//不可以修改。

  4.将引用用于对象

    类对象传递给函数时,c++通常是使用引用。

    string对象操作示例:

string  & vesiona(string & a,string & b){
return a;
}
versiona("abc","baf");

    这里需要注意一点就是:C-style字符串和string之间有个转换过程。

    对象、继承和引用。

    基类引用可以指向派生类对象。即如果在函数声明中是一个基类的引用。则可以用派生类对象作为参数。例如参数类型为  ostream &d的函数,可以接受cout对象。也可以接受ofstream对象。

 

函数中的默认参数

 

函数重载:并不区分const和非const变量。

 

函数模板:

  

template <typename AnyType>
void swap(AnyType & a){}

    这里有显示具体化,可以了解一下。

 

内存模型和名称空间:

  1.编译时,需要注意的点:程序一般分为三个部分:头文件、源代码文件(代码总体结构)、源代码文件(调用的函数)。头文件一般包含:函数原型,符号常量,结构、类、模板声明,内联函数。

    需要注意的:不要将头文件加入项目列表中,也不要在源码中 使用include来包含源代码文件。

    同一个文件中只能包含一个头文件一次,所以头文件中要用这行代码来进行处理:

#ifndef A_H_
#define A_H_

...

#endif

 

  2.存储持续性:

    自动存储持续性:函数定义的变量为自动。执行时被创建,执行完被释放。**栈的特性。register:指出定义的变量是自动的。

    静态存储持续性:函数外定义的变量或者用static定义的为静态存储,一直存在。static来声明。默认值为0。函数内的为静态局部变量,无链接性。函数外用static的是全局,并且链接性为内部。不用static的为静态全局、外部链接性。

    动态存储持续性:用new创建的。被称为自由存储或堆。

    线程存储持续性:生命周期和线程一样长。用关键字thread_local来声明的。

  3.作用域和链接

    作用域:名称多大范围内可见。函数中的变量只能在函数中可见。文件中对文件内函数都可见。

    作用域局部变量,只在代码块({})内有效。函数原型的只在参数列表中可见,因此可以省略。类中成员对整个类可见。名称空间,在整个名称空间内可见。

    C++函数的作用域是整个类或整个名称空间的,否则不能调用。

    链接:描述了名称如何在不同单位之间共享。链接性为外部的可以在文件间共享。自动变量没有链接性。

    链接性为外部的:在一个文件中定义,在另一个文件中用引用声明,extern

    1.cpp

    

int a

 

    2.cpp

extern int a

    作用域解析运算符:(::)

    说明符和限定符

    说明符:auto (C++11 delete) register static  extern  thread_local  mutable(用来指出被const限定后,仍然可以修改的数据)

      const 全局变量链接性为内部的,和使用了static说明符类似。

    限定符:const  volatile(即使程序代码没有改变,值仍然有可能发生改变,硬件方面的改变。)

 

函数和链接性:

  也可以用static来限制链接性。

常规new运算符和定位new运算符。

 

名称空间:声明自己的名称空间:

namespace  myth{
int a;
double b;
}

使用名称空间:

using  myth::a;
using std::cin
using 声明
using namespace std;

 

 

类与对象:

  类:我们为什么要使用类?这是因为在处理一些复杂的问题时,我们从问题的本身来思考如何进行编程。从数据的角度来进行组织代码。从基本数据类型和复合类型中,我们可以看出:一种数据类型说明了三个方面:

    1.类型决定了数据的存储量。

    2.决定了如何解释内存中的位(float和long占据的位相同,但转换为数值的方式不同)

    3.决定了可以进行的操作和方法。

    类就是我们自定义的一种类型。我们可以自己定义上面几点。

    

class  a{
int a;
double b;
char * pt;
}
类的声明
class A{
//默认是 private
public:
  A();
protect:  

}
访问控制

  类的成员函数:可以在类中声明。在类外定义,但此时要注意(::)。内联函数注意添加关键词inline(定义时。)

 

  类的构造函数和析构函数:const ,利用const声明对象时,成员函数在后面加const的才可以调用。因此我们可以约定,只要类方法不修改对象的值,就可以将其声明为const。

  this指针:this的应用。*this。

  类作用域。

    类中常量的声明:不能用const,因为类声明只是描述了形式,但没有创建对象。解决的方法有:

      1.在类中声明一个枚举。2.使用关键词static。但这个常量会被所有对象共享。从这个可以利用  class 来进行枚举。可以使枚举量重名。但这样就不能隐式转换为整型。

  用类实现抽象数据类型。

 

  运算符重载:operator 关键词。这与友元函数有联系。可以利用友元函数来进行运算符重载。友元函数将原型放在类声明中,并使用关键字 friend。

  类的自动转换和强制类型转换。构造函数可以将某种类型转换为类类型。转换函数进行相反的操作。

 

  类的虚函数和纯虚函数(抽象类):运行中,动态绑定。

    虚函数的声明:在基类中,用关键词virtual来声明。

    纯虚函数:就是没有定义,在类中,代码格式为:

virtual  void func()=0;

    使用场景:如果你希望派生类重新定义一个成员函数,那么你应该在基类中把此函数设为virtual。

        多态:以单一指令调用不同函数。这就是利用虚函数实现的。(基类指针调用派生类方法)。

        ********为什么要把基类指针可以指向派生类对象。这样做的目的,是为了实现多态,给不同派生类对象传递相同的信息,可以产生不同的行为。为了实现这种思想,添加了虚函数。虚函数的意义就是基类中没有实现,在派生类实现。而我们用基类声明的指针,可以指向派生类的对象,调用成员函数时,同名函数就会调用派生类的虚函数。9999999999999999999999999999999999999999999999999

        如果抽象类的函数不打算被使用,我们就不应该定义它,使用纯虚函数。即拥有纯虚函数的类是抽象类。

        抽象类不能产生对象实例。但是我们可以利用抽象类的指针,以便于操作抽象类的各个派生类。

        虚函数派生下去,仍然是虚函数,因此派生类中可以省略virtual关键字。

posted @ 2018-09-19 21:04  昔时  阅读(507)  评论(0编辑  收藏  举报