一,C++基础知识
1,面向对象的三大特征:继承,封装,多态,多态的通过重载和覆盖体现。 2,虚函数。虚函数是动态绑定的基础。允许在派生类中其实现可以和基类的不一样。 不是重载声明而是覆盖,不能声明为静态方法,派生类同原型函数都自动为虚函数。 通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用那个对象方法。 虚析构函数,需要通过基类指针删除派生类对象时声明虚析构函数。构造函数不能是虚函数。 纯虚函数是一个在基类中声明的虚函数,基类中不再给出函数的实现,派生类实现函数体。 带有纯虚函数的类称为抽象类class Name { virtual 类型 函数名(参数表)=0; //纯虚函数 ... } 抽象类只能作为基类来使用,抽象类自身无法实例化,即不能声明抽象类的对象。 3,容器 vector,list,set,map,stack,deque, 4,算法 STL Algorithm,迭代器,sort,unique,find,search,remove, 5,模板:模板函数、函数模板,模板类、类模板。 6,泛型 泛型在C++中的主要实现为模板函数和模板类。 7,printf可以支持#args格式定制,sprintf和sscanf可以格式化字符串,警惕空格。 8,private,protected,protected继承时属性变化。private 属性不能够被继承。 使用private继承,父类的protected和public属性在子类中变为private; 使用protected继承,父类的protected和public属性在子类中变为protected; 使用public继承,父类中的protected和public属性不发生改变; 9,重载,覆盖/重写,隐藏 重载,指的是同名函数,形参个数或者形参类型不一样,实现了动态调用,跟返回值无关。 派生类的函数与基类的函数同名,但是参数不同。不论有无virtual关键字,基类的函数将被隐藏(混淆重载)。 派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。基类的函数被隐藏 10,在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。 如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的, 在C++不区分共同占用同一块内存区。 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改 (当然,你要通过非正当手段也可以修改,而且方法很多) 11,static, const 和 static const 变量的初始化问题 static修饰的是静态变量,静态函数。对于类来说,静态成员和静态函数是属于整个类的,而不是属于对象。 static变量在类内部声明,但是必须在类的外部进行定义和初始化。 const常量在类内部声明,但是定义只能在构造函数的初始化列表进行。 static声明静态成员是解决同一个类的不同对象间数据和函数共享问题 const类型的对象必须进行初始化,而且不能被更新。const成员函数不更新对象的数据成员 extern 关键字告诉编译器存在着一个变量/函数,保证这个变量/函数已经定义 12,析构函数和构造函数都不能有返回值。派生类方法覆盖时方法体内用Base::func()调用父类方法(非静态) 13,this指针存在于类的成员函数中,指向被调用函数所在的类实例的地址。this作用域是在类内部 14,前向引用 向引用声明,但是在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象。 15,拷贝构造函数 当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值 17,构造函数可以是私有函数,外部无法调用创建对象。单例模式类内部提供一个静态方法创建对象供访问。 18,组合类中的成员数据是另一个类的对象。(另一个类的对象是该类中的成员) 19,友元是一个类主动声明哪些其他类或函数是朋友,进而可享受本类的访问特权。 20,字节对齐,针对结构体GCC#pragma push(1) #pragma pack() MS C++用VC代码项调整默认8字节; 22,大端小端,指多字节全部反序,大端低字节高地址(表同)。小端低字节低地址(全反),大小端仅指字节间的顺序 比如四个字节32位int数据0x12345678 用小端表示内存假设递增: 78 56 34 12 字节内不动,更大数据同理 23,extern "C" {} 可以避免C代码被C++编译器符号改变 #ifdef __cplusplus #endif可以判断有C++代码 24,__FILE__及__LINE__及__FUNCTION__可以用做调试。 #warning #error可以加在代码中guard编译问题 25,函数指针(int (*pfc)();)——指针函数(int* fun();) 数组指针(int (*pa)[8];)——指针数组(int* ap[8];) 函数指针(int (*pfc)();)——指针函数(int* fun();) 数组指针(int (*pa)[8];)——指针数组(int* ap[8];) 类模板-函数模板 template <typename T> class Vector { … }; template <typename T> void fun(T a) { … }; 模板函数fun<int>、fun<double>、fun<Shape*> template<typename T> // 模板声明 T add(T a,T b) { return a+b; } // 模板函数 注意形参和返回值的类型 模板类Vector<int>、Vector<char> template <class Type> // Compare<int> C1(3,5); class Compare { public: Type Compare(Type a,Type b){ int c = a+b; } }; 26,智能指针 auto_ptr是C++标准库中()为了解决资源泄漏的问题提供的一个智能指针类模板(注意:这只是一种简单的智能指针) auto_ptr的实现原理其实就是RAII,在构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载。 auto_ptr<string> pstr(new string("abcd")); // success 赋值,参数传递的时候会转移所有权 pb(pa) pa->…; //Error auto_ptr<string> pstr = new string("abcd"); // error 由于构造函数声明为explicit,因此只能显示调用构造函数 auto_ptr 不能共享所有权,即不要让两个auto_ptr指向同一个对象。 auto_ptr 不能指向数组,因为auto_ptr在析构的时候只是调用delete,而数组应该要调用delete[]。 auto_ptr 只是一种简单的智能指针,如有特殊需求,需要使用其他智能指针,比如share_ptr。 auto_ptr 不能作为容器对象,STL容器中的元素经常要支持拷贝,赋值等操作,在这过程中auto_ptr会传递所有权, 那么source与sink元素之间就不等价了。 shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象,shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占) shared_ptr 的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放, 环状的链式结构shared_ptr将会导致内存泄漏(可以结合weak_ptr来解决) std::shared_ptr<int> ptrb = std::make_shared<int>(b); //std::shared_ptr<int> ptrb = pb; //error weak_ptr是为了配合shared_ptr而引入的一种智能指针,weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。lock()获取指针 unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现) 27,mac和vector迭代器遍历差异 for(myMap::iterator it=myMap.begin(); it!=myMap.end(); it++) // it->first it->second for(myVec::iterator it = myVec.begin(); iterB != myVec.end(); ++iterB) // iterB->size() (*iterB).size() Day* day = new Day() // Day day("getInstance");
二,数据结构和算法
C++ 标准库 继承封装多态 STL 容器队列堆栈 模版 范型 框架 Restful API <algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、 <memory>、<numeric>、<queue>、<set>、<stack>、<utility> 向量(vector) 连续存储的元素<vector> 列表(list) 由节点组成的双向链表,每个结点包含着一个元素<list> 双队列(deque) 连续存储的指向不同元素的指针所组成的数组<deque> 集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列, 没有两个不同的元素能够拥有相同的次序 <set>多重集合(multiset) 允许存在两个次序相等的元素的集合 栈(stack) 后进先出的值的排列 <stack> 队列(queue) 先进先出的执的排列 <queue> 优先队列(priority_queue) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列 <queue> 映射(map) 由{键,值}对组成的集合,以某种作用于键对上的谓词排列 <map> 多重映射(multimap) 允许键对有相等的次序的映射 <map>
三,C++设计模式
1,C++设计模式 单例模式,工厂模式,策略模式,适配器模式,原型模式,模板模式, 建造者模式,外观模式,组合模式,代理模式,桥接,装饰,观察者模式 2,JAVA设计模式 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、 备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。 3,常用设计模式解释 1)单例模式:类只有一个全局对象,实现一个单例有两点注意事项, ①将构造器私有,不允许外界通过构造器创建对象; ②通过公开的静态方法向外界返回类的唯一实例。 class DanliModule{ public: ~DanliModule(){}; static DanliModule& instance() { //DanliModule* danlim = new DanliModule(); static DanliModule danlim; return danlim; } bool getName(){ return false; } //DanliModule(){}; static int isCount; const bool isFound; private: DanliModule():isFound(false){}; }; int DanliModule::isCount = 0; 2)工厂模式:专门创建一个工厂类,这个类根据传进不同的参数,来创建不同的实例,被创建的实例都会有一个抽象的父类 //产品的基类 class Product{ public: //基类中的纯虚函数 virtual int operation(int a, int b) = 0; }; //产品的子类Add class Product_Add : public Product{ public: int operation(int a, int b){ return a + b; } }; //产品的子类Mul class Product_Mul : public Product{ public: int operation(int a, int b){ return a * b; } }; //工厂 class Factory{ public: Product* Create(int i){ switch (i){ case 1: return new Product_Add; break; case 2: return new Product_Mul; break; default: break; } } }; int main() { Factory *factory = new Factory(); int add_result = factory->Create(1)->operation(1, 2); int mul_result = factory->Create(2)->operation(1, 2); cout <<"op_add:" <<add_result << endl; cout <<"op_multiply:" << mul_result << endl; getchar(); return 0; } 3)代理模式:为其他对象提供一种代理以控制对这个对象的访问 例如:抽象接口是工厂,主体是继承工厂生产手机,代理主体是富士康使用工厂生产手机。 class Image { public: Image(string name): m_imageName(name) {} virtual ~Image() {} virtual void Show() {} protected: string m_imageName; }; class BigImage: public Image { public: BigImage(string name):Image(name) {} ~BigImage() {} void Show() { cout<<"Show big image : "<<m_imageName<<endl; } }; class BigImageProxy: public Image { private: BigImage *m_bigImage; public: BigImageProxy(string name):Image(name),m_bigImage(0) {} ~BigImageProxy() { delete m_bigImage; } void Show() { if(m_bigImage == NULL) m_bigImage = new BigImage(m_imageName); m_bigImage->Show(); } }; int main() { Image *image = new BigImageProxy("proxy.jpg"); image->Show(); delete image; return 0; }