C++基础知识学习笔记

基本语法ios

C面向过程思想:程序=(数据结构)+(算法)
 数据结构与算法分离,以算法(函数)为主。c++

C++面向对象思想:程序=(数据结构+算法)
 数据结构(属性)与算法(操做)绑成一个类,定义一个个对象
对象=(数据结构+算法)  ,程序=(对象+对象+对象+……)程序员

面向对象程序设计的程序员有两类:
1.面向对象应用程序设计
2.类库的设计算法

头文件:类的声明            ---类的外部接口
       (成员函数在类声明中实现时,通常很简短,默认为内联函数)
源文件:类的成员函数定义     ---类的内部实现编程


c++新增关键字:
namespace  using  class
private protected public
bool true false
this new delete
friend explicit mutable  virtual  operator inline  template
catch throw try
static_cast dynamic_cast const_cast reinterpret_cast数组

1.命名空间
namespace  myspace  //命名空间(至关于声明一个类)
{
 int num=100;//变量
 void show() //函数
 {
  cout<<"num= "<<num<<endl;
 }
 namespace myspace1
 {
  int num =150;
 }
};缓存

2.iostream.h  C92标准
  iostream    C99标准 std;安全

3.输入输出
cin>>   标准输入
cout<<  标准输出
cerr<<  标准错误输出
clog<<  错误输出(有缓冲)数据结构


4.布尔类型
   bool flag; 只能存放false 0和true 1 两种状态。
   flag = true ;
   flag = false;
   flag = 3 ;此时flag只能为true(1);app

5.const
const num=12;//只读变量,定义时必须初始化。


6.引用和指针

区别:
1.非空: 引用不能为空,定义的时候必须初始化(指针能够为空,不初始化)
2.合法性:使用的时候不须要再验证期合法性。(指针使用的时候须要验证其合法性)
3.不可修改:初始化对象以后不可修改,但标示的变量值可变。(指针灵活,可随意修改所指对象及对象值)
4.应用场合:引用通常用在对象固定的单个变量,不能是数组。
5.引用不用分配内存,节省内存空间,适用于较大数据参数传递。

int count = 11;
int num = 12;
int &ref = num; //1.同一个内存空间,不一样的名字 2.定义的时候必须初始化 3.标示对象固定,值可变
ref = count;
const int &ref=num;//常引用:便可提升效率,又保护数据不更改。
注意:char &ref="hello"是不对的,hello是const类型的常字符串,不能转换为char类型引用。

void myswap(int *n1, int *n2)//另开辟一指针变量空间存地址,其指向对象可改变,灵活。

void myswap(int &n1, int &n2) //可修改同一块内存空间的值。简单方便。但其标示对象不可变。

将“引用”做为函数参数有哪些特色?
(1)传递引用给函数与传递指针的效果是同样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,因此在被调函数中对形参变量的操做就是对其相应的目标对象(在主调函数中)的操做。
(2)使用引用传递函数的参数,在内存中并无产生实参的副本,它是直接对实参操做;而使用通常变量传递函数的参数,当发生函数调用时,须要给形参分配存储单元,形参变量是实参变量的副本;若是传递的是对象,还将调用拷贝构造函数。所以,当参数传递的数据较大时,用引用比用通常变量传递参数的效率和所占空间都好。
(3)使用指针做为函数的参数虽然也能达到与使用引用的效果,可是,在被调函数中一样要给形参分配存储单元,且须要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另外一方面,在主调函数的调用点处,必须用变量的地址做为实参。而引用更容易使用,更清晰。


返回引用注意:
(1)不能返回局部变量的引用。主要缘由是局部变量会在函数返回后被销毁,所以被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用,虽然不存在局部变量的被动销毁问题,可对于这种状况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是做为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就没法释放,形成memory leak。
(3)能够返回类成员的引用,但最好是const。 主要缘由是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值经常与某些其它属性或者对象的状态有关,所以有必要将赋值操做封装在一个业务规则当中。若是其它对象能够得到该属性的很是量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
(4)流操做符重载返回值申明为“引用”的做用:
流操做符<<和>>,这两个操做符经常但愿被连续使用;赋值操做符=。这个操做符象流操做符同样,是能够连续使用:x=y=10;
(5)在另外的一些操做符中,不能返回引用:+-*/ 四则运算符。它们不能返回引用,主要缘由是这四个操做符没有side effect,所以,它们必须构造一个对象做为返回值.


何时须要“引用”?
流操做符<<和>>、赋值操做符=的返回值、拷贝构造函数的参数、赋值操做符=的参数、其它状况都推荐使用引用

7.内联函数
编译的时候直接替换成函数体,不须要分配栈空间,节省了时间。
适合于简短代码,不能有while switch等复杂结构流程语句。

#define  A(x)   x   在预处理的时候替换,无参数类型的制约,c++中通常不用
inline  fun1(int a)

inline  string dbtest (int a ,int b)  //声明的时候加上 inline
void main()

 dbtest(3,4)     
}

string dbtest(int a,int b)   //函数体,适用代码短,无复杂结构控制语句,无递归函数
{
 return a+b;           
}

 

8.内存分配
C:(函数)
//malloc分配的特色:1.按字节分配,返回void类型地址 2.不进行初始化 3.须要#include<stdlib>
int *p;
p = (int *)malloc(100 * sizeof(int));
free(p);
                
C++:new(关键字)
在C++中,类的建立若是用malloc则绕过了构造函数,不是一个真正的类建立。只是分配内存而已。
用new申请的是一个类对象的内存空间,调用了构造函数,因为堆是手动分配,不用的时候须要用delete手动释放,delete调用析构函数释放内存空间。否则容易形成内存泄露。反复new和delete容易形成内存碎片。

若是对象的数据成员包含指向堆空间的指针,必须自定义深拷贝构造函数,须要用new为建立的对象分配堆空间
通常自定义的拷贝构造函数都须要一个自定义的析构函数来释放额外的资源。

//new分配的特色:1按对象类型分配,返回对象类型地址 2.默认方式初始化 3.不须要头文件
Student *p;
p = new Student[5];
delete [] p;  //单一标量时。用 delete p;

A *p=new A; //会调用无参构造
A *p=new A[10];//调用10次无参构造,在堆上分配对象数组,只能调用无参构造,不能在跟参数。
A *p=new A(10); //调用有参构造
A *p=new A(a1);//调用拷贝构造
A *p=new A(*p);//调用拷贝构造

delete [] p;// 调用了析构函数。

**********************************************************************************
                 ---类和对象---


面向过程:C  功能分解,
面向对象(Object Oriented):C++  责任分解
特征:1.抽象(abstract) 2.封装(encapsulation)
 3.继承(inheritance) 4.多态(polymorphism)

类:同类型对象抽象出共性造成类
对象:是类的一个实例,除了具备类的共性之外,还会有本身的特性
关系:类是对象的一种抽象描述,对象是类的实例化

c++中,类与结构体区别:
1.结构体是类的一种特例,class能够改成struct。
2.未指定访问权限时,类中成员默认为私有,而结构体默认为公有。
3.通常,数据--结构体;  数据+操做行为--类

this指针:
1.类的全部对象调用的成员函数都是同一段代码,不一样对象在调用函数的时候,会传给函数的隐含形参this指针一个本身的地址,至关于this=&s,这样函数操做就知道是哪一个对象的数据了,也就是成员函数能够直接访问数据成员而无需对象名的缘由。
2.对象的数据在main函数的栈里,别的函数不能直接访问,因此要传入对象的地址。(至关于传址调用)
3.线程中建立线程函数中的函数参数通常不能是c++的成员函数,由于在类中定义的成员函数编译的时候会自动加上this指针。(能够将该函数设定为static静态成员函数或者友元函数)


重载:类中容许多个同名不一样参函数,编译器根据函数名和参数肯定不一样的函数调用。
重写(覆盖):子类从新定义父类虚函数。迟滞联编,运行的时候动态调用子类的函数。

类成员函数的重载、覆盖和隐藏区别?
a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不一样;
(4)virtual 关键字无关紧要。
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不一样的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则以下:
(1)若是派生类的函数与基类的函数同名,可是参数不一样。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)若是派生类的函数与基类的函数同名,而且参数也相同,可是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆


类大小:有它数据成员(不含static数据)所占空间决定。(类的成员函数不占内存空间)

class  <类名>
{
      public:
                 <公有数据成员和成员函数>;
      protected:
                 <保护数据成员和成员函数>;
    private:
                 <私有数据成员和成员函数>;

};
<各个成员函数的实现>;


---数据成员---

私有成员:private  :自身类(+友元类)
 要访问:1.加友元friend  2.用接口函数获得其值。

保护成员:protected :自身类(+友元类)+派生类

共有成员:public:自身类(+友元类)+派生类+其余类和函数 ==任何代码


静态成员:
静态数据成员:面向对象中使用静态数据成员替代全局变量,能够增长安全性和更好的封装重用特性。
静态成员函数:
*static数据成员:public:
       static int count;
      int Student::count =88;  //定义和初始化静态成员。
                  cout<<"count=" <<Student::count<<endl;//类的静态成员,通常经过类来访问。
   1. 在类中定义,在类外初始化(加域限定符),放在类的内部实现.cpp文件中。
         (不能放在类声明里面,也不能在.cpp文件中main函数前面)。
   2.属于类,不属于某个对象,存储于全局数据区,程序运行前便已分配内存和初始化。
        3.public类型静态数据能够在类外共享,private/protected只可在类内部访问,不能用this限制.
   4.利用类名直接访问(也能够利用对象访问)

        使用场合:通常用在保存流动变化的对象个数,
                 做为一个标志指示一个特定动做是否发生,
                 指向一个链表的头结点或尾节点。

 static +成员函数
        1.静态成员函数中没有this参数传入。
   2.通常为public,使用类名直接调用。

        public:
  static A * createObj()  //用static函数里new调用构造函数。
  {
   A *obj=new A;     //可调用构造函数
   return obj;
  }
         A * p= A::createObj();     //调用static函数

常成员
const+数据成员:const int num; 
 1.只读变量。
 2.容许int a[num]
 3.必须在构造函数的初始值表中初始化。
 Student() : num(10) {}
const+成员函数:void fun() const
      不能修改类中的数据成员(除了mutable int a;)

      

this指针:this->name
1.调用成员函数的时候将对象的指针做为隐含的参数传到行为函数中,联通对象(栈)和函数。使得函数可直接使用对应的对象中的数据成员。
2.this不能用在静态成员。
    

---成员函数---

构造函数 :类的独特性使得它对数据成员有保护性,不能随意赋值来初始化,能够用一个成员函数来专门进行初始化。为了方便,则让他在定义一个对象的时候自动调用特殊的成员函数(即构造函数)进行分配内存和初始化。

类型:
无参构造
有参构造

初始化方式:
a.函数体内赋值(已分配空间)。
b. 经过初始值表在分配空间的同时赋值。A(int _a):a(_a){},通常用于常量和引用。
  注意:构造对象成员的时候,得看类中声明的顺序,不是看冒号后面成员初始化的顺序。
加explicit表示确切赋值,阻止隐式赋给对象的成员(A a1=200;)

定义对象:(类的实例化)
Student st1;   //调用无参构造
          //不能是Student st1();由于C++会认为是声明了一个名叫st1的普通函数,返回Student类型。
Student st2(2,"xiaoming",80); //调用有参构造


1.定义对象的时候自动调用,给对象初始化
2.构造函数名和类名相同,没有返回类型
3.可重载,根据参数类型和顺序自动调用相对应构造函数。
4.默认会生成一个空的无参构造函数,只负责分配内存不进行初始化。(全局为0,局部为随机)
  一旦本身定义一个构造函数,那么默认的无参构造函数将再也不提供。(记得手动加上无参构造函数)
5.构造函数能够是private(可利用public中static函数调用private中的构造函数来构造新对象)

无参构造函数
Student() {} 

有参构造函数
Student(int nu, char *na, float sc) {}

拷贝构造函数:
1.使用已经存在的对象来生成新的对象
Student(Student &b){} 
Student st4(st1); //显式调用拷贝构造函数
Student st5=st2;  //隐式调用拷贝构造函数(不是赋值)

当里面有指针时:
a.浅拷贝:A(A & _a1)
      {
        this->p=_a1.p;
      }
拷贝后指针指向同一个内存,使用时会发生错乱。
b.深拷贝:A(A & _a1)
      {
         p=new char[10];
   strcpy(p,_a1);
      }

手动实现拷贝构造函数。连指针指向的对象一块儿拷贝

2.当函数的形参是类的对象,实参传递给形参调用函数的时候。
//String & _s =s1 没有调用拷贝构造,仅是取了另外一个名字。s表明s1自己;  节约内存。
//String  s=s1;  调用了拷贝构造函数,另分配了临时空间s;
Book test1(Book b)
{
    return b;
}
test1(book2);
3.函数的返回类型为对象类型的时候。
String    返回的是一个值, 不能返回局部变量地址,返回一个临时对象,返回后当即释放。
String &  返回的是一块内存,不能是局部变量内存,能够是全局变量。
String & operator +(String& _s)


析构函数
1.释放对象以前自动调用,手动释放堆,按栈的顺序(先构造后释放)释放内存空间。
2.函数名为~类名,没有返回类型
3.,没有参数,不能够重载
4.默认会生成一个空的析构函数。
5.析构函数必须是public

其余自定义接口函数:
 float get_score() //读取数据成员,对于类中只包含有get而不包含有set的属性叫只读属性
 {
     return score;
 }
 void set_score(float sc)  //修改数据成员,包含有set方法的数据成员叫作可写的属性
 {
         score = sc;
 }

带有默认值参数的函数
省去了多个函数因参数不一样而进行重载,默认值的参数通常是从右到左
int add(int a=2,int b=1) {}
cout<<add(10,20)<<endl;
cout<<add(10)<<endl;


友元:
 友元超越了类的封装,在类外容许访问类的私有数据成员,带来性能提高和编程的灵活性。  
 1.友元函数(普通函数 + 类的成员函数)
 函数声明在类声明中,实现必须放在要访问的类的实现以后。(注意:不属于类的成员函数)
 friend float avg_score(Student *ps, int count);
 friend void Teacher::set_stu_score(Student &ps, float sc);

 2.友元类:能够用该类全部成员函数访问私有数据成员
 该友元类的定义应放在有私有数据声明前面。
 friend class Teacher;

     
          ­
*******************************************************************************
                ---类的继承和派生---

父类(基类)
 ↓
子类(派生类)
1.实现继承:所有继承,无需额外编码
2.接口继承:仅使用属性和方法,在子类中实现(抽象基类)
2.可视继承:子窗体使用父窗体的外观和实现代码


子类声明:
此时,子类拥有了父类的属性和方法,还能够本身添加独有的属性和方法,也能够从新实现或重载。

单继承格式:
class  <派生类名> :<继承方式> <基类名>
{
 public: //派生类新定义成员
 protected:
 private:
}

1.继承的方式--数据成员的访问权限:

private  :公有,保护-> 私有 (基类中私有数据不能在派生类中访问,更不能在其余类和函数中访问)

protected:公有 -> 保护     (基类中保护数据能够在派生类中访问,不能在其余类和函数中访问  )

public:   全部不变。        (基类中公有数据能够在派生类中访问,也能够在其余类和函数中访问)

1.私有数据在任何方式下继承都是不能访问的。
2.保护数据在私有继承的状况下只能在派生类中访问,继续继承则不能访问了。
3.公有数据在公有继承状况下都能访问。

2.构造函数的实现方式:
注意: 1.派生类不能初始化基类中的私有数据。
 2.默认为先调用基类的无参构造函数,再调用派生类的构造函数。
因此:通常能够指定调用基类构造函数的方式(注意按照基类构造函数的参数顺序进行传递)。
 使得用合适的基类构造基类的数据,派生类构造派生类的数据。
Car::Car(float ai, float sp, int to) : Vehicle(to, sp)

3.成员函数的实现方式:
a.仅继承基类的成员函数
  则直接调用基类的版本。

b.对基类成员函数进行了从新的实现(同名同参)
基类函数没有virtual关键字,原来的基类成员函数被隐藏
只调用派生类的成员函数   lex.show();
能够经过基类名::成员函数 的方式调用基类的版本。
lex.Vehicle::show();

c.对基类成员函数进行了从新的实现(同名不一样参)
无论基类函数有没有virtual关键字,原来的基类成员函数被隐藏
只能调用派生类的成员函数  lex.stop(3);
能够经过基类名::成员函数 的方式调用基类的版本。
lex.Vehicle::stop();

 

多态
同一个基类有多个派生类,每一个派生类有相同方法名,不一样方法体,容许将子类的地址赋值给父类指针或引用。
多态实现条件:
1.必须是公有继承
2.必须是基类指针或引用对象
3.必须是虚函数

多态的做用:
1)隐藏实现细节,使得代码可以模块化;扩展代码模块,实现代码重用;
2)接口重用,为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用

基类指针或引用能够指向派生类对象
base1 *c1=new child;
c1->fun();

虚函数
virtual修饰的基类方法
一样一个操做,在继承中的不一样对象经常须要不一样的实现。好比学生和研究生的学费计算。称为多态。
基类和子类都是属于基类的,用基类的指针或引用调用基类和子类都有的同名同参的函数时,须要根据不一样的对象类型调用不一样的函数,用virtual表示该函数为迟后联编(late binding),运行的时候才知道调用哪一个对象的函数。这样即可实现用一个函数操做即可以管理全部的继承的对象。
1.只有成员函数才能是虚函数,静态成员函数、内联函数、构造函数不能是虚函数。
2.析构函数须要针对不一样对象析构不一样对象,能够是虚函数。

1.虚函数在基类中必须实现函数。
2.虚函数能够被派生类重写,没有重写时调用基类函数。

纯虚函数
程序在功能分解过程当中,高层次的类只用来继承,没有必要实例化,称为抽象类,抽象类为其余类继承服务。
其子类对其纯虚函数进行了实现,则不是抽象类了。
里面的函数只有声明没有实现,称为纯虚函数。纯虚函数为子类保留一个位置,使得在多态中可使用子类的实在函数覆盖原来的位置。否则基类的指针找不到该成员函数会报错。
方法体为0的虚函数,在每一个派生类(要实例化)中必须实现函数。
virtual char* what()=0;

抽象类
只要包含有一个纯虚函数的类为抽象类
1.抽象类通常为基类
2.抽象类能够包含其余的实虚函数
3.抽象类不能被实例化,但能够声明一个抽象类的指针或引用。
4.派生类若是没有重写基类的纯虚函数,该派生类也为抽象类

 

动态联编与静态联编
动态联编和静态联编只能在多态时使用
动态联编:在调用时,肯定基类指针指向对象
静态联编:在编译时,肯定基类指针所指对象


虚函数表

类大小计算

1.没有数据成员大小为1
2.没有虚函数的类,只给非静态成员变量分配空间
3.派生类继承基类的全部成员大小
4.有虚函数的基类会多分配4个字节大小存放虚表地址
5.派生类继承全部基类的存放虚表地址空间
6.派生类本身的方法再也不分配空间,替换基类的方法或默认添加到第一个基类虚表后面

虚表(v-table)
保存类中虚函数的地址
包含虚函数类的对象:前四个字节确定是虚表地址


多继承
一个子类继承多个父类:
1.编译程序问题:构造的顺序
2.模糊性问题:多个基类具备相同方法名,到底调用哪个。

虚基类
主要是用来解决多个基类具备相同的方法名的问题,派生类继承多个基类时,发现存在虚基类则构造,后加入的虚基类用前面的那个。
class  base
class base1:virtual public base
class base2:virtual public base
class child:public base1,public base2
包含虚基类构造顺序:
1.首先构造虚基类
2.构造非虚基类


**********************************************************************************
        ---模板---

函数模板
函数模板避免了针对相同操做、不一样数据类型须要屡次重载不一样的函数的局限。
template<class T,class T1,.....>
T fun(T a,T1 b)
{
    ...
}
函数模板:声明了一个通用类型参数的函数,编译时不为其产生任何代码。
模板函数:编译系统发现具体的函数调用的时候自动匹配,找到函数模板就重载一个实际的模板函数。

类模板
在定义类时,类中的数据类型能够不肯定,可是在实例化对象时指定数据类型

C++中为何用模板类:
 (1)可用来建立动态增加和减少的数据结构
(2)它是类型无关的,所以具备很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型

template<class T,class T1>
class A
{
 public:
  A(T _a,T1 _b);
     T1 max();
  T min();
 private:
  T a;
     T1 b;
};
  template<class T,class T1>
  T1 A<T,T1>::max()
  {
     return b;
  }

A<int,char> a1(2,'a'); //实例化类对象时必需要指定数据类型     

函数模板与类模板有什么区别:
函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。

友元模板类

templat<class T>
clas B;//前置声明B为模板类

template <class T>
class A
{
    friend class B<T>;  //说明模板类B为友元类
};
template <class T>
class B
{
}

模板类继承


异常处理

异常
正在运行程序发生错误
异常是可能也可能不发生,根据程序运行的环境或输入值有关
一旦发生异常,程序中止运行,不会退出程序

异常处理:
1.抛出异常  throw
2.捕捉异常  try
3.处理异常  catch

try
{
    throw except("b==0 is error"); //抛出异常
}

catch(base& e)
{
    cout<<e.what()<<endl;
}


c++如何调用c的函数

c++是一种不完全的面向对象语言,为了和c兼容,它能够定义不属于任何类的全局变量和函数。
可是为了支持函数的重载,C++对函数的处理方式为:
int add(int a,int b)
c++编译以后函数为: add_int_int
c编译以后函数为:add

通常文件结构:
#ifndef __INCxvWorksh
#define __INCxvWorksh

#ifdef __cplusplus
extern "C"
{
#endif

/*C code*/

#ifdef __cplusplus
}
#endif

extern "C":1.按照c编译语法编译
           2.extern表示它修饰的全局变量和函数能够在本模块和其余模块中使用


判断一段程序是由C 编译程序仍是由C++编译程序编译的:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endi

//指向对象的数据成员指针
int *p=&(a1.x);
cout<<*p<<endl;

//指向类中的成员函数指针
int (A::* fun) ();  
fun=&A::getX;
cout<<(a1.*fun)()<<endl;


符号重载(重写)
符号重载:给符号赋予新的功能
至关于一个特殊的成员函数或者友元函数,只是函数名为符号。
s1+s2至关于 s1.+(s2)  :s1调用 名字为‘+’的成员函数

符号
运算符号:+ - * / %
比较符号:> >= <  <= != ==
逻辑符号:&& ||
位运算符号:& | ^ ~
赋值符号:= += -=
特殊符号:[] . , :: -> * &


可用做重载的运算符:
 算术运算符:+,-,*,/,%,++,--
  位操做运算符:&,|,~,^,<<,>>
  逻辑运算符:!,&&,||;
  比较运算符:<,>,>=,<=,==,!=;
  赋值运算符:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=;
  其余运算符:[],(),->,,(逗号运算符)

不能重写的符号:
 .
 ::
 *
 ?:
 sizeof

符号重写语法:
返回值类型  operator  重写符号(参数)

符号重载方式:
1.类的成员方式重载
2.友元函数方式重载
 
符号重写特色:
1.不能改变符号的结合性
2.不能改变符号的优先级
3.不能改变符号元数(一元符号 二元符号)
4.不能创造符号

类的成员方式重写与友元方式重写特色:
a.类的成员方式重写特色
  1.一元符号,能够写成无参数(this指针代替)
  2.二元符号,能够写成只有一个参数(this指针代替另外一参数)
  3. =,(),[] 和-> 只能是成员方式重写
b.友元方式重写特色
  1.一元符号,必须有一个参数
  2.二元符号,必须两个参数
  3.<<, >>只能使用元方式重写

 

C++流

全部流的基类:ios(抽象类) -->istream ,ostream ,fstreambase,strseambase
  istream +fstreambase --> ifstream
  ostream +fstreambase --> ofstream

  istream +strseambase --> istrstream
  ostream +strseambase --> ostrstream 

  istream +ostream  --> iostream
  iostream+fstreambase  --> fstream
  iostream+strseambase  --> strstream

头文件:iostream: ios,istream,ostream,iostream,
   fstream : fstreambase,ifstream,ofstream,fstream, +<iostream>
       strstream:strstreambase,istrstream,ostrstream,strstream +<iostream>

标准输入输出流:istream ostream iostream

文件流:ifstream(读文件) ofstream(写文件) fstream
文件(键盘)  ==》 内存   读入   in
文件(屏幕) 《==  内存   写出   out
字符串流: istrstream  ostrstream  strstream

 

输入/输出流的控制
输入流:cin
输出流:cout cerr  clog(日志)
cout:标准输出,与缓存关联
cerr:错误输出,无缓存
clog:日志输出,与缓存关联

'\n' endl  回车 清空缓存

#include<iomanip> 输入输流控制的头文件
输入输出流的控制符
#include<iomanip>   I/O流控制头文件
dec                                              设置整数的基数为10
hex                                              设置整数的基数为16
oct                                              设置整数的基数为8
setfill(c)                                       设置填充字符c,c能够是字符常量或字符变量
setprecision(n)                                  设置有效数字个数
setw(n)                                        设置字段宽度为n位

setiosflags(ios::scientific)                     设置浮点数以科学计数法(即指数)显示
setiosflags(ios::left)                           输出数据左对齐   
setiosflags(ios::right)                          输出数据右对齐   
setiosflags(ios::uppercase)                      在以科学计数法输出E和以十六进制输出字母X时以大写表示
setiosflags(ios::showpos)                       输出正数时给出“+”号

控制输出格式的流成员函数
precision(n)    设置实数的精度为n位
width(n)        设置字段宽度为n位
fill(c)         设置填充字符c
setf()          设置输出格式状态  
unsetf()        终止已设置的输出格式状态     


格式状态标志
 
ios_base::left
左对齐输出,用于输出
 
ios_base::right
右对齐输出,用于输出
 
 
ios_base::dec
转换基数为十进制,用于输入或输出
 
ios_base::oct
转换基数为八进制,用于输入或输出
 
ios_base::hex
转换基数为十六进制,用于输入或输出
 
ios_base::showbase
输出时显示基指示符(0表示八进制,0x或0X表示十六进制),用于输入或输出
 
 
ios_base::uppercase
输出时表示十六进制的x为大写,表示浮点数科学计数法的e为大写,用于输出
 
ios_base::showpos
正整数前显示“+”符号,用于输出
 
ios_base::scientific
用科学表示法显示浮点数,用于输出
 

 

 


文件流:
ifstream:读文件
ofstream:写文件

文件流操做文件模式:
ios::in:读文件
ios::out:写文件(建立文件,清空间文件,写入)
ios::app:写文件追加
ios::ate:写文件追加
ios::binary:二进制文件
ios::trunc:清空文件内容

out,trunc和app模式只能用于指定与ofstream或fstream对象关联的文件

in模式只能用于指定与ifstream或fstream对象关联的文件

流构造:
ifstream(char* filename,mode)

关闭流
close(ifstream)//清空缓存(缓存中的内容写入到文件)


get
语法:
  istream &get( char &ch );
  istream &get( char *buffer, streamsize num );
  istream &get( char *buffer, streamsize num, char delim );

get()函数被用于输入流:
读入一个字符并把它存储在ch,
读取字符到buffer直到num - 1个字符被读入, 或者碰到EOF或换行标志,
读取字符到buffer直到已读入num - 1 个字符,或者碰到EOF或delim(delim直到下一次不会被读取)


getline
语法:
  istream &getline( char *buffer, streamsize num );
  istream &getline( char *buffer, streamsize num, char delim );

getline()函数用于输入流,读取字符到buffer中直到下列状况发生:
num - 1个字符已经读入,
碰到一个换行标志,
碰到一个EOF,
或者,任意地读入,直到读到字符delim。delim字符不会被放入buffer中。


块读写
read(char * buf,int size);//通常与输入流使用
write(char * buf,int size);//通常是与输出流使用

size:写入或读取的字节数(n*sizeof(class))


标准模板库

C++:1:面向对象设计思想,抽象封装,继承多态,标准类库
     2:泛型程序设计思想(generic programming),模板机制,STL

STL :Standard Template Library(数据结构+算法)
容器 :可容纳各类数据类型的数据结构。
算法:用来操做容器中的元素的算法函数。

容器
分类:
第一类容器:
1.顺序容器:vector,list,deque
2.关联容器:set(multiset)  map(multimap) (key)

第二类容器:
3.容器适配器:stack,queue,priority_queue

vector
1.vector是一种顺序容器,元素是存放在一段连续空间。
2.至关于可以存听任意类型的动态数组,代替C类型的。
3.在数组末尾增删元素时间固定,中间增删时间与该元素后面个数成正比。
4.支持随机存储。
5.能够用下标[],at(),迭代器访问,at在运行时会检查容器大小,更安全。

构造vector
 vector();                                          //无参构造
 vector(size_type num, const TYPE &val );           //有参,放入num个val
 vector( const vector &from );                      //拷贝构造
 vector( input_iterator start, input_iterator end );//[start,end)区间元素
读取:
 begin(); //返回第一个元素的迭代器
 end(); //指向当前vector末尾元素的下一位置的迭代器

 rend();  // 返回Vector起始的逆迭代器
 rbegin();// 返回Vector尾部的逆迭代器
 
 TYPE at( size_type loc );//返回当前Vector指定位置loc的元素的引用.
     //v.at(i)
 front(); //返回第一个元素
 back();  //返回最后一个元素

增:
 void push_back( const TYPE &val ); //存放元素到容器末尾
  //push_back(20);
 iterator insert( iterator loc, const TYPE &val );
  //vector<int>::iterator it1=v1.insert(it,2000);//插入新元素到it指定元素前面
  //cout<<*it1<<endl;//返回值为迭代器执行插入元素位置 
      void insert( iterator loc, size_type num, const TYPE &val );
  //v1.insert(it,5,1);//在it所指元素前插入5个1;
      void insert( iterator loc, input_iterator start, input_iterator end );
  //v1.insert(it,v2.begin(),v2.end());//在指定位置it前插入区间[begin, end)的全部元素

删:
 pop_back();  //移除容器的末尾元素
 clear();     //清空全部元素

 iterator erase( iterator loc );  //删除指定元素
  v1.erase(v1.begin()+3);//经过迭代器删除容器中的元素
      iterator erase( iterator start, iterator end );
  v1.erase(v1.begin(),v1.begin()+4);//删除指定区间元素
改:
 void assign( input_iterator start, input_iterator end ); //将区间[start, end)的元素赋到           当前vector
   void assign( size_type num, const TYPE &val );//赋num个值为val的元素到vector中

 void swap( vector &from );//swap()函数交换当前vector与vector from的元素
  v1.swap(v5);//交换容器

查:
 #include <algorithm>   find为宏函数
  vector<int>::iterator it=find(v1.begin(),v1.end(),20);//查找find(算法函数)
  判断元素是否存在
     if(it==v1.end())
   cout<<"not find"<<endl;
  else
             v1.erase(it);

运算:v1 == v2   1.它们具备相同的容量  2. 全部相同位置的元素相等
   v1 != v2
   v1 <= v2
   v1 >= v2
   v1 < v2
   v1 > v2
   v[]

其余:
 size();    // 返回Vector元素数量的大小
  void resize( size_type size, TYPE val ); //改变Vector元素数量的大小
 max_size();// 返回Vector所能容纳元素的最大数量(上限)
 capacity();//返回vector所能容纳的元素数量(在不从新分配内存的状况下)
 empty();   // 判断Vector是否为空(返回true时为空)

 

 


迭代器
是一个自定类型,指向容器中元素的指针,每一种容器都有对应迭代器
 
迭代器分类:
1.通常迭代器
通常迭代器定义
vector<int>::iterator it;
2.只读迭代器(只能访问容器元素,不能修改)
只读迭代器定义
vector<int>::const_iterator it;
3.反转迭代器
反转迭代器定义
vector<int>::reverse_iterator it;

list 链表容器
1.元素按顺序储存在链表中.与向量(vectors)相比, 它容许快速的插入和删除,可是随机访问却比较慢.
2.能够存听任何数据类型的动态链表
3.在任何位置插入删除都是常数时间
4.不支持随机存储。
5.

    
构造
 list()
 list(list& l)
 list(a,a+3);

在顺序容器中新增长的函数:

push_front: 在前面插入
pop_front: 删除前面的元素
merge: 合并两个链表,并清空被合并的那个
sort: 排序( list 不支持STL 的算法sort)
reverse: 颠倒链表
remove: 删除和指定值相等的全部元素
unique: 删除全部和前一个元素相同的元素
splice: 在指定位置前面插入另外一链表中的一个或多个元素,并在另外一链表中删除被插入的元素


pair 
pair<int,string>
pair<list<int>::iterator,list<int>::iterator>


set关联容器
有序存放元素值
set容器构造
set<int> s1;
set<int,cmp>
set容器中元素值必定是惟一

multiset关联容器与set容器功能同样,但容许出现相同值的元素

map
一种key-value元素对容器
map<key,value>
key特色:
1.只读
2.惟一
3.根据key排序

map构造
map<string,int>

multimap关联容器与map容器功能同样,容许出现相同键值

练习:1.实现vector list容器

相关文章
相关标签/搜索