C++学习之路

C++内容概述:

day01 入门

part 1

C语言+面向对象思维实现面向对象                   面向对象的思维方式

1、定义结构体{成员变量;函数指针}

2、定义全局函数,函数参数必须带一个参数,为结构体类型的指针;

3、产生一个结构体,并对结构体赋值:成员变量赋值、函数指针赋值为全局函数;

4、使用结构体变量,注意函数指针成员的使用还必须指定参数;例如:t.run(&t);

   给结构体部分成员赋值:用点的方式来赋值

   struct Time t = {.show=show,  .tick=tick , .run=run};

part 2

主要内容:面向过OP+面向对象(OOP+泛型(<T>+标准模板库(STL

1、创建类class A {};自定义数据类型

2、创建对象,A a;由类可以产生无数对象

3、使用对象(利用对象去做事情,a.doSomething())

showa);OP

a.show();OOP

面向过程OP

面向对象OOP

函数层次复用

类层次复用

struct Screen {};  

movestruct Screen* p);

class Screen {}

screen s

s.move();

按步骤设计

按功能设计

 

 

 

 

 

 

 

 

 

C++语言主要内容:

1、构造函数:

功能:创建对象的标志;初始化成员变量;

特点:(1)名字和类名相同Time::Time();(2)没有返回值;(3)创建对象的时候自动调用;

理解:(1)自定义了构造函数,不论是否带参数,则系统不再分配默认构造函数;

例子:

void  func()

{

A a1;        // 正确

A a2();     // 错误,函数申明,不会创建对象;

A a310);

A a4 = 10

A a5 = A5); // 创建无名对象赋值给a5,一共创建了2个对象

A();        // 无名对象

A* p=new A(4); // 创建堆对象

A* p = new A [4] //  创建对象数组

delete [ ] p; 

}

2、析构函数:

功能:用来释放资源

特点:(1Time::~Time();(2)没有返回值,没有参数;(2)对象生命期结束时自    动调用

 

3、初始化列表:

语法:在构造函数的申明和函数体之间,写法,Aint i):i成员(形参){}

必须用初始化列表初始化的:

(1)常量;

(2)引用,从一而终,必须初始化,且只能初始化一次,对引用的赋值就是对引用从事的变量的赋值;

(3)

     int i;  int j;  

     int &b=i;    // bi的别名

     b = j        // j的值复制给b,也就是赋值给ib是从一而终的)

哲学原理:具体问题具体分析,特殊问题特殊对待 

(4)成员对象;

(5)父类的成员; 

 

4、this指针

指向当前对象的指针,每个成员函数都有一个隐藏的this指针,在调用成员函数的时候自动将对象的地址给this指针;

 

5、常量对象,只能访问常函数(注意const在名字和大括号之间)

const A a

const A::show()const {};  

 

6、A  a4=4; A  a5=A(5); A a6=A6   三种方式是等同的,等同于A5);

   强制类型转换 == 拷贝构造函数

 

   例如:double i=5   double  i=double(5)    double  i=(double)5  double  i(5)

day02 进阶

1、拷贝构造函数(盲点)

功能:复制对象

特点:

1)用户不定义拷贝构造函数,则有一个系统分配的copy构造函数,逐字节拷贝;

2)用户一旦自己定义了copy构造函数,系统不再自动分配copy构造函数

定义必须为Bconst B& b,这样实参形参传递才不会重复拷贝,从而陷入死循环;

      编译器将BB b)这种陷入循环拷贝的形式禁止了;利用了引用不拷贝对象的   特性;

 

拷贝构造的调用形式:   B  ba)  =   B  b = a第二种由编译器优化第一种

class A{};

void fn(A aaA  ab){// A aa=a1;  A ab=a2;}

void fn2(const A& aa, const  A& ab){}

void gn(){ 

   A a;         // 如果为static,或者全局,返回要调用拷贝构造

   return  a;  // inline优化,没有调用拷贝构造

}  

A  a1; 

A  a2=a1;    // copy

A  a2(a1);   // copy

fn(a1,a2);    // copy

fn2(a1,a2);   

A a4 = gn();  只拷贝一次,inline优化,返回时没有调用拷贝构造

如果 gn内部的astatic或者全局的,则gn返回时候要拷贝

 

深拷贝、浅拷贝,为什么要自定义拷贝构造函数?

(1)拷贝构造函数默认逐字节拷贝:如果一个类中有指针变量,则会出现浅显拷贝;内存释放的时候会出现double free错误;

  C++学习之路

2深拷贝,自定义拷贝构造函数,实现拷贝后每个对象有自己的堆空间,即自己的指针指向自己的堆空间;

 

法则:一旦类中有指针,必须自定义拷贝函数,实施深拷贝;

 

2、返回引用:(特殊问题特殊对待

   int&  funcvoid) ,不能返回局部变量的引用,因为引用的实体已经消失了。

 

错误:

        C++学习之路 

  

技巧点:C++规定,对于临时对象如果有一个引用,那么这个临时对象的生命期会延长。

        但引用需要申明为常引用;

C++学习之路 

 

3、静态成员、静态成员函数(局限在类中的全局变量、全局函数)

语法:静态成员在编译时分配空间并初始化,写程序时在类外写初始化语句,格式为下,

         class A{static  string   a; static void fn();}  // 内部声明,外部定义

          string  B::a = liurong;

理解:

1)相当于是一个全局变量,只是这个全局变量有了类的限定而已,只在类内部是全局的;

2)按照上面理解,必须在外部定义静态变量,并初始化,类内部只是申明了一下而已

3)静态函数中不能访问非静态成员,因为对象可能还没有创建;

 

4、继承

派生类的构建:构建子类之前要先构建父类,可以在初始化表中选择性调用父类构造函数;

 

派生类的构造函数:初始化表中调用父类构造函数,如果不显式调用,则使用父类无参数                 

                   因此一般在父类中一般都要定义一个无参构造函数。

 

同名覆盖(overwrite当父类行为无法满足子类需要时需要重写

1)子类中中有一个和父类同名的函数show,则子类调用show是调用自己的show

     即所谓的overwrite

(2)子类同名函数中,要调用父类的同名函数,必须用域作用符:Father::show(),这样show函数就青出于蓝了:

 

保护继承:protected为继承而生,本类中protectedprivate相同,子类可以访问父类protected成员(protected成员:本类中和子类中可以访问)

 

初始化列表:

 

A:必须放在初始化列表初始化:

   常变量、引用、成员对象带参构造函数、父类对象带参构造函数

B:不能放在初始化列表初始化:数组、结构体

 

5sizeof运算符

1A asizeofA) = sizeofa),只与类型有关,与内容无关;

2)一个空类的大小时1个字节,原因是:编译器给定,主要是为了保证空类产生对象;

     保证c++中所有对象都是唯一的;

 

6、单子模式

方法1:静态局部变量

    返回静态局部对象指针的静态函数(静态函数,返回静态对象指针,构造函数私有)

最初的一种想法:构造函数的私有属性:创建对象的前提是至少有一个公有的构造函数,构造函数为私有成员,则无法创建对象;但构造函数为私有,无法创建哪怕1个对象,因此此方案不可行;

改进:

(1)构造函数为私有;

(2)写一个static的返回对象指针的函数,在static函数创建一个静态对象; 

         并返回静态对象的地址

C++学习之路 

 

方法2:使用静态成员变量

C++学习之路 

 

7、关于初始化列表的深入:

C++学习之路 

 

法则:默认情况下,创建一个对象访问别人的无参构造函数,如果没有无参构造函数,就必须主动调用有参构造函数;

 

8、访问修饰符、继承方式

继承时,publicprotectedprivate逐级降低访问权限:

(1)父类的私有成员子类不可访问,也就是说子类看不见;

(2)public不改变父类publicprotected的访问权限;

     protected将父类publicprotected改为protected

     privatepublicprotected改为privated

 

9、多态

用父类的指针指向子类的实例,可以调用子类的函数!

用父类的引用指向子类的实例,可以调用子类的函数!

注意:用子类的实例构造父类的实例,会出现子类对象的分割,因此不能调用子类的函数!

 

day04 提高

1、常指针、常对象

常引用可以指向一个常量,也可以指向一个非常量(常的东西更加通用)

理解:

(1)常指针只能指向一个对象,以后不能修改指针的值;

(2)常对象不能修改,只能有指向常对象的指针来指向;

技巧:赋值兼容和强制转换必须坚持一个原则,类型像精确兼容,访问权限不能升高;

 

2、内部类:成员内部类、局部内部类

优点:

1)隐藏名字,避免命名冲突;

2)提供统一的内部类名,统一个各个类的处理方法(迭代器)

2)将异常类封装为内部类;

语法:

(1)class A{publicclass B},使用方法:A::B  b

(2)void f(){class A{}A a}

理解:内部类可以当成外部类的静态成员类型看待,同时受访问修饰符的限定;

 

3、protected继承方式下,派生类对象的指针不能直接转换成指向基类对象的指针;

 

4、友元函数、友元成员:

友元:一个函数或者一个类的成员要访问一个类的成员,必须被一个类授权为友元

友元的申明:(1)友元类:friend  func();(2)友元类:friend class B

注意:友元关系不能继承、不能反转

 

关于访问的理解:

类外面访问:c.member

类里面访问(不带点的访问):(1)本类里面访问;(2)子类里面访问;  

 

5、运算符重载:

什么时候:当默认运算符不能满足我们的运算要求时候;

重载本质:编写新的运算符重载函数;

(1)重载单目运算符:

(2)重载双目运算符;

(3)强制类型转换运算符重载,operator int(){return   x}

 C++学习之路 

 

6c++工具,异常处理:try语句块,catch过滤器处理,throw抛出异常

(1)将可能出现异常的语句放在try语句块中,并在可能语句出抛出异常throw

(2)try语句块之后设置过滤器catch,并在catch中设置各种类型的参数来捕获各种可      能的异常,并处理,例如:catchint &  e)。

(3)注意:catch(。。。)可以捕获各种可能的异常。

(4)异常不仅可以在产生异常的当前函数中捕获,一个函数中产生的异常可以在调用者来捕获并处理;(异常可以在外层函数中捕获,并且经常这么做

C++学习之路 

 

可以讲try语句块中的内容写成一个函数,try{fn();},同样可以捕获异常

 

7、多重继承和虚拟继承(multi_virtual

虚拟继承:继承时添加virtual关键字,将公共基类申明伟虚拟基类

作用:A直接派生类采用虚拟继承方式,A间接派生类D只保留公共基类的一份拷贝

C++学习之路 

                          day05 深入(STL+泛型编程)

1、IO

C++学习之路 

标准IO(控制台IOconsole IO

cincoutcerrclog

注意:cerrclog不支持重定向,只能输出到屏幕

 

1istream:的成员函数

>>:

get():获取一个字符,例如:char=cin.get()  或者 cin.get(ch)

getline()获取一行字符,遇到指定的终止字符时提前结束

         获得一个字符串,例如:cin.getlinebufsizeofbuf),‘\n’),用buf去获              得,用‘\n’结尾buf缓冲区,实际获取sizeofbuf-1个字符;

         当输入内容超过buffersize-1个,cin流出错,需要调用cinclear()清除;

注意:全局的getlineiostream&string& s,分隔符)

clear():清除错误标志,当输入的字符数目大于接收缓冲区大小,cin出错,此时cin  需要clear来清除错误才能重新恢复正常工作,例如:cin.clear()

read():

ignore():忽略n个字符,遇到指定的终止字符时候

         清除缓冲区,例如:cin.ignorelen,‘\n’),忽略100或者‘\n’之前的字符

peek():查看数据,不取走,查看输入缓冲区的第一个字符,例如根据字母或者数字  来区分年龄和名字

putback():将数据放回到缓冲区

 

2ifstreamifstream fin(“filename”);char ch = fin.get();cout<<ch;fin.close();

fin seekg(),finseekp();

3ofstrreamios::binarywindow下二进制写);ios::app(接着写)

4ostrream:

 

文件操作的步骤:

① 建立文件流对象;

② 将文件流对象和对应的文件建立对应关系;

③ 指定文件工作方式:输入文件还是输出文件(ios::out ios::in);文本文件还是

二进制文件ascii文件还是data文件;

对于12步,可以一次完成(调用文件流类的带参构造函数);

对于12步,可以二次完成(建立文件流对象、调用open函数);

 

C++学习之路 

operator<<:向屏幕输出

put():     输出单个字符,返回ostream的引用

fill():     coutfill(‘#’)设置填充为#     永久操作

write():   coutwritebufferlen

width():   coutwidth10),设置宽度为10一次性操作

setf():     ios::  leftrightdecocthexshowbaseshowpointuppercaseshowpos    ios:: scientific

 

输出控制符:<iomanip>

定点数就是以小数形式输出小树,输出的就是定点数;浮点数就是以科学技术法输出,输出的就是浮点数,setiosflagsios::fixed)和setiosflagsios::scientific)只能用一个,同时用后面用的无效;

iomaip的控制符都是setxxxx的形式,decocthexendlsetiosflagsresetiosflags

流对象成员函数则是以名词形式:coutxxxxsetfunsetf

理解:

控制符应该是一些预定义的对象,在用重载的<<输出的时候,这个预定义的对象利用cout调用cout流成员对cout的属性进行了一些修改,本质上是一样,就是封装和重载;

char a[10];  cin>>a;其实完成了2件事,1是从键盘获取输入到流,2是部分流提取到a

 

(4)持久化:ofstream fout(“xxx”);foutwritechar*, size);

 

2、模板(函数模板、类模板)template <typename T>

技巧点返回引用的函数调用可以充当左值;一般的函数调用不能充当左值;

 

STLstandard template library

1  概述:C++刚开始没有STL,后来由HP公司开发并作为编译器的一部分作为C++标准

组成部分:

(1)模板类(容器):

(2)模板函数(通用算法):

(3)迭代器,iterator,智能指针:容器和通用算法之间的桥梁,将二者结合到一起;

 迭代器的本质就是指针,可以模拟指针的功能;

 

概念的理解:

(1)容器+通用算法+迭代器 构成的一整套体系 = STL标准模板库

(2)所有通用算法都是针对iterator的;

(3)区间:用两个迭代器表示的一段范围叫做区间,[beginend,end指向的不是区间的    一部分;

(4)迭代器的实现原理:内部类+指针,所有STL容器都有一个内部iterator类;

 

2  容器的分类:

C++学习之路 

(1)序列式容器(顺序型容器):基于链表实现

vector(向量,动态数组):

list(双向链表):

deque(双端队列):

 

(2)适配器:stack栈、queue队列、priority queue优先队列

 

(3)关联式容器():基于二叉查找树,查找速度非常快

set

multiset

map

multimap

3  通用算法

(1)foreach遍历算法;

(2)findvector::iterator beginvector::iterator endT t)区间内查找算法;

 

4、实例

vector的构建:

(1)指定大小构建;vector<double> v1;

(2)使用一个vector的子区间构建;vector<double>  v2(5);// 指定容量为5个元素

(3)拷贝构建;vector<double> v3(v1)

(4)迭代器构建:用v1的子区间(前两个元素)构建

     C++学习之路

vector的大小:sizeofvector=12,因为2iterator+1个容量=12Bytes

vector添加元素:push_back();

vector遍历:

     (1)迭代器遍历:

  C++学习之路

     (2)下标遍历:

  C++学习之路

 (3)下标遍历(2):

  C++学习之路

  用at(下标)可以捕获异常,用

   try{}   

   catchexception&  e) cout<<e.what()<<endl;
vector 插入:

insert()

vector删除:

erase()

 

5、RTTI 运行时类型识别

T  t;cout<<typeid().name()<<endl;

 

 

Qt C++编程调试记录

1、C++学习之路

给非常成员函数传递了一个常对象this指针,丢弃了const修饰符后传递给this

说明:

(1)非常成员函数的this指针必须是指向一个非常对象

(也就是:非常对象才可以调用非常成员函数,因为非常函数可能试图修改对象)

(2)常成员函数的this指针可以指向非常对象也可以指向常对象,因此更加通用  

2、关于对齐:min4maxsizeofmember)))

 

转载于:https://my.oschina.net/u/1772925/blog/375259