diff --git a/DesignPattern/AbstractFactoryPattern/Factory.cpp b/DesignPattern/AbstractFactoryPattern/Factory.cpp new file mode 100644 index 0000000..4ad2e7c --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/Factory.cpp @@ -0,0 +1,25 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#include "Factory.h" +#include "concrete_factory.h" + +Factory* Factory::CreateFactory(FACTORY_TYPE factory) +{ + Factory *pFactory = nullptr; + switch (factory) { + case FACTORY_TYPE::BENZ_FACTORY: // 奔驰工厂 + pFactory = new BenzFactory(); + break; + case FACTORY_TYPE::BMW_FACTORY: // 宝马工厂 + pFactory = new BmwFactory(); + break; + case FACTORY_TYPE::AUDI_FACTORY: // 奥迪工厂 + pFactory = new AudiFactory(); + break; + default: + break; + } + return pFactory; +} \ No newline at end of file diff --git a/DesignPattern/AbstractFactoryPattern/Factory.h b/DesignPattern/AbstractFactoryPattern/Factory.h new file mode 100644 index 0000000..b00ed46 --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/Factory.h @@ -0,0 +1,24 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_FACTORY_H +#define DESIGNPATTERN_FACTORY_H + +#include "product.h" + +// 抽象工厂模式 +class Factory { +public: + enum FACTORY_TYPE { + BENZ_FACTORY, // 奔驰工厂 + BMW_FACTORY, // 宝马工厂 + AUDI_FACTORY // 奥迪工厂 + }; + + virtual ICar* CreateCar() = 0; // 生产汽车 + virtual IBike* CreateBike() = 0; // 生产自行车 + static Factory * CreateFactory(FACTORY_TYPE factory); // 创建工厂 +}; + +#endif //DESIGNPATTERN_FACTORY_H diff --git a/DesignPattern/AbstractFactoryPattern/FactoryMain.cpp b/DesignPattern/AbstractFactoryPattern/FactoryMain.cpp new file mode 100644 index 0000000..b819e2d --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/FactoryMain.cpp @@ -0,0 +1,46 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#include "Factory.h" +#include "product.h" +#include "FactoryMain.h" +#include +using namespace std; + +void FactoryMain() +{ + // + Factory * pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BENZ_FACTORY); + ICar * pCar = pFactory->CreateCar(); + IBike * pBike = pFactory->CreateBike(); + + cout << "Benz factory - Car: " << pCar->Name() << endl; + cout << "Benz factory - Bike: " << pBike->Name() << endl; + + SAFE_DELETE(pCar); + SAFE_DELETE(pBike); + SAFE_DELETE(pFactory); + + // + pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BMW_FACTORY); + pCar = pFactory->CreateCar(); + pBike = pFactory->CreateBike(); + cout << "Bmw factory - Car: " << pCar->Name() << endl; + cout << "Bmw factory - Bike: " << pBike->Name() << endl; + + SAFE_DELETE(pCar); + SAFE_DELETE(pBike); + SAFE_DELETE(pFactory); + + // µ + pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::AUDI_FACTORY); + pCar = pFactory->CreateCar(); + pBike = pFactory->CreateBike(); + cout << "Audi factory - Car: " << pCar->Name() << endl; + cout << "Audi factory - Bike: " << pBike->Name() << endl; + + SAFE_DELETE(pCar); + SAFE_DELETE(pBike); + SAFE_DELETE(pFactory); +} \ No newline at end of file diff --git a/DesignPattern/AbstractFactoryPattern/FactoryMain.h b/DesignPattern/AbstractFactoryPattern/FactoryMain.h new file mode 100644 index 0000000..e1cfe21 --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/FactoryMain.h @@ -0,0 +1,14 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_FACTORYMAIN_H +#define DESIGNPATTERN_FACTORYMAIN_H + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if(p) {delete(p); (p)=nullptr;}} +#endif + +void FactoryMain(); + +#endif //DESIGNPATTERN_FACTORYMAIN_H diff --git a/DesignPattern/AbstractFactoryPattern/concrete_factory.h b/DesignPattern/AbstractFactoryPattern/concrete_factory.h new file mode 100644 index 0000000..8de0baf --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/concrete_factory.h @@ -0,0 +1,51 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_CONCRETE_FACTORY_H +#define DESIGNPATTERN_CONCRETE_FACTORY_H + +#include "Factory.h" +#include "concrete_product.h" + +// 奔驰工厂 +class BenzFactory : public Factory +{ +public: + ICar* CreateCar() + { + return new BenzCar(); + } + IBike* CreateBike() + { + return new BenzBike(); + } +}; + +// 宝马工厂 +class BmwFactory : public Factory +{ +public: + ICar* CreateCar() { + return new BmwCar(); + } + + IBike* CreateBike() { + return new BmwBike(); + } +}; + +// 奥迪工厂 +class AudiFactory : public Factory +{ +public: + ICar* CreateCar() { + return new AudiCar(); + } + + IBike* CreateBike() { + return new AudiBike(); + } +}; + +#endif //DESIGNPATTERN_CONCRETE_FACTORY_H diff --git a/DesignPattern/AbstractFactoryPattern/concrete_product.h b/DesignPattern/AbstractFactoryPattern/concrete_product.h new file mode 100644 index 0000000..fef09bb --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/concrete_product.h @@ -0,0 +1,72 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_CONCRETE_PRODUCT_H +#define DESIGNPATTERN_CONCRETE_PRODUCT_H + +#include "product.h" + +/********** 汽车 **********/ +// 奔驰 +class BenzCar : public ICar +{ +public: + string Name() + { + return "Benz Car"; + } +}; + +// 宝马 +class BmwCar : public ICar +{ +public: + string Name() + { + return "Bmw Car"; + } +}; + +// 奥迪 +class AudiCar : public ICar +{ +public: + string Name() + { + return "Audi Car"; + } +}; + +/********** 自行车 **********/ +// 奔驰 +class BenzBike : public IBike +{ +public: + string Name() + { + return "Benz Bike"; + } +}; + +// 宝马 +class BmwBike : public IBike +{ +public: + string Name() + { + return "Bmw Bike"; + } +}; + +// 奥迪 +class AudiBike : public IBike +{ +public: + string Name() + { + return "Audi Bike"; + } +}; + +#endif //DESIGNPATTERN_CONCRETE_PRODUCT_H diff --git a/DesignPattern/AbstractFactoryPattern/product.h b/DesignPattern/AbstractFactoryPattern/product.h new file mode 100644 index 0000000..4d62240 --- /dev/null +++ b/DesignPattern/AbstractFactoryPattern/product.h @@ -0,0 +1,25 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_PRODUCT_H +#define DESIGNPATTERN_PRODUCT_H + +#include +using std::string; + +// 汽车接口 +class ICar +{ +public: + virtual string Name() = 0; +}; + +// 自行车接口 +class IBike +{ +public: + virtual string Name() = 0; +}; + +#endif //DESIGNPATTERN_PRODUCT_H diff --git a/DesignPattern/AdapterPattern/AdapterMain.h b/DesignPattern/AdapterPattern/AdapterMain.h new file mode 100644 index 0000000..8e58cba --- /dev/null +++ b/DesignPattern/AdapterPattern/AdapterMain.h @@ -0,0 +1,21 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_ADAPTERMAIN_H +#define DESIGNPATTERN_ADAPTERMAIN_H + +#include "adapter.h" + +void AdapterMain() +{ + // + IRussiaSocket * pAdapter = new PowerAdapter(); + + // + pAdapter->Charge(); + + SAFE_DELETE(pAdapter); +} + +#endif //DESIGNPATTERN_ADAPTERMAIN_H diff --git a/DesignPattern/AdapterPattern/adaptee.h b/DesignPattern/AdapterPattern/adaptee.h new file mode 100644 index 0000000..679c378 --- /dev/null +++ b/DesignPattern/AdapterPattern/adaptee.h @@ -0,0 +1,20 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_ADAPTEE_H +#define DESIGNPATTERN_ADAPTEE_H + +#include + +// 自带的充电器(两脚扁型) +class OwnCharger +{ +public: + void ChargeWithFeetFlat() + { + std::cout << "OwnCharger::ChargeWithFeetFlat\n"; + } +}; + +#endif //DESIGNPATTERN_ADAPTEE_H diff --git a/DesignPattern/AdapterPattern/adapter.h b/DesignPattern/AdapterPattern/adapter.h new file mode 100644 index 0000000..ecb94f5 --- /dev/null +++ b/DesignPattern/AdapterPattern/adapter.h @@ -0,0 +1,34 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_ADAPTER_H +#define DESIGNPATTERN_ADAPTER_H + +#include "target.h" +#include "adaptee.h" + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } +#endif + +// 电源适配器 +class PowerAdapter : public IRussiaSocket +{ +public: + PowerAdapter() : m_pCharger(new OwnCharger()){} + ~PowerAdapter() + { + SAFE_DELETE(m_pCharger); + } + void Charge() + { + // 使用自带的充电器(两脚扁形)充电 + m_pCharger->ChargeWithFeetFlat(); + } +private: + // 持有需要被适配的接口对象(自带的充电器) + OwnCharger* m_pCharger; +}; + +#endif //DESIGNPATTERN_ADAPTER_H diff --git a/DesignPattern/AdapterPattern/target.h b/DesignPattern/AdapterPattern/target.h new file mode 100644 index 0000000..cbe7cfa --- /dev/null +++ b/DesignPattern/AdapterPattern/target.h @@ -0,0 +1,16 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_TARGET_H +#define DESIGNPATTERN_TARGET_H + +// 俄罗斯提供的插座 +class IRussiaSocket +{ +public: + // 使用双脚圆形充电(暂不实现) + virtual void Charge() = 0; +}; + +#endif //DESIGNPATTERN_TARGET_H diff --git a/DesignPattern/BridgePattern/BridgeMain.cpp b/DesignPattern/BridgePattern/BridgeMain.cpp new file mode 100644 index 0000000..00324cd --- /dev/null +++ b/DesignPattern/BridgePattern/BridgeMain.cpp @@ -0,0 +1,30 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#include "BridgeMain.h" + +void BridgeMain() +{ + // ơȣ + IElectricalEquipment * light = new Light(); + IElectricalEquipment * fan = new Fan(); + + // أʽءλأ + // ʽغ͵ƹλغͷȹ + ISwitch * pullChain = new PullChainSwitch(light); + ISwitch * twoPosition = new TwoPositionSwitch(fan); + + // ơص + pullChain->On(); + pullChain->Off(); + + // 򿪷ȡرշ + twoPosition->On(); + twoPosition->Off(); + + SAFE_DELETE(twoPosition); + SAFE_DELETE(pullChain); + SAFE_DELETE(fan); + SAFE_DELETE(light); +} \ No newline at end of file diff --git a/DesignPattern/BridgePattern/BridgeMain.h b/DesignPattern/BridgePattern/BridgeMain.h new file mode 100644 index 0000000..01ef6eb --- /dev/null +++ b/DesignPattern/BridgePattern/BridgeMain.h @@ -0,0 +1,17 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_BRIDGEMAIN_H +#define DESIGNPATTERN_BRIDGEMAIN_H + +#include "refined_abstraction.h" +#include "concrete_implementor.h" + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} } +#endif + +void BridgeMain(); + +#endif //DESIGNPATTERN_BRIDGEMAIN_H diff --git a/DesignPattern/BridgePattern/abstraction.h b/DesignPattern/BridgePattern/abstraction.h new file mode 100644 index 0000000..82cdd59 --- /dev/null +++ b/DesignPattern/BridgePattern/abstraction.h @@ -0,0 +1,23 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_ABSTRACTION_H +#define DESIGNPATTERN_ABSTRACTION_H + +#include "implementor.h" + +// 开关 +class ISwitch +{ +public: + ISwitch(IElectricalEquipment *ee){ m_pEe = ee; } + virtual ~ISwitch(){} + virtual void On() = 0; // 打开电器 + virtual void Off() = 0; // 关闭电器 + +protected: + IElectricalEquipment * m_pEe; +}; + +#endif //DESIGNPATTERN_ABSTRACTION_H diff --git a/DesignPattern/BridgePattern/concrete_implementor.h b/DesignPattern/BridgePattern/concrete_implementor.h new file mode 100644 index 0000000..35a2daa --- /dev/null +++ b/DesignPattern/BridgePattern/concrete_implementor.h @@ -0,0 +1,44 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H +#define DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H + +#include "implementor.h" +#include + +// 电灯 +class Light : public IElectricalEquipment +{ +public: + // 开灯 + virtual void PowerOn() override + { + std::cout << "Light is on." << std::endl; + } + // 关灯 + virtual void PowerOff() override + { + std::cout << "Light is off." << std::endl; + } +}; + +// 风扇 +class Fan : public IElectricalEquipment +{ +public: + // 打开风扇 + virtual void PowerOn() override + { + std::cout << "Fan is on." << std::endl; + } + //关闭风扇 + virtual void PowerOff() override + { + std::cout << "Fan is off." << std::endl; + } +}; + + +#endif //DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H diff --git a/DesignPattern/BridgePattern/implementor.h b/DesignPattern/BridgePattern/implementor.h new file mode 100644 index 0000000..c8b801e --- /dev/null +++ b/DesignPattern/BridgePattern/implementor.h @@ -0,0 +1,17 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_IMPLEMENTOR_H +#define DESIGNPATTERN_IMPLEMENTOR_H + +// 电器 +class IElectricalEquipment +{ +public: + virtual ~IElectricalEquipment(){} + virtual void PowerOn() = 0; // 打开 + virtual void PowerOff() = 0; // 关闭 +}; + +#endif //DESIGNPATTERN_IMPLEMENTOR_H diff --git a/DesignPattern/BridgePattern/refined_abstraction.h b/DesignPattern/BridgePattern/refined_abstraction.h new file mode 100644 index 0000000..48be107 --- /dev/null +++ b/DesignPattern/BridgePattern/refined_abstraction.h @@ -0,0 +1,53 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_REFINED_ABSTRACTION_H +#define DESIGNPATTERN_REFINED_ABSTRACTION_H + +#include "abstraction.h" +#include + +// 拉链式开关 +class PullChainSwitch : public ISwitch +{ +public: + PullChainSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} + + // 用拉链式开关打开电器 + virtual void On() override + { + std::cout << "Switch on the equipment with a pull chain switch." << std::endl; + m_pEe->PowerOn(); + } + + // 用拉链式开关关闭电器 + virtual void Off() override + { + std::cout << "Switch off the equipment with a pull chain switch." << std::endl; + m_pEe->PowerOff(); + } +}; + +// 两位开关 +class TwoPositionSwitch : public ISwitch +{ +public: + TwoPositionSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} + + // 用两位开关打开电器 + virtual void On() override + { + std::cout << "Switch on the equipment with a two-position switch." << std::endl; + m_pEe->PowerOn(); + } + + // 用两位开关关闭电器 + virtual void Off() override { + std::cout << "Switch off the equipment with a two-position switch." << std::endl; + m_pEe->PowerOff(); + } +}; + + +#endif //DESIGNPATTERN_REFINED_ABSTRACTION_H diff --git a/DesignPattern/CMakeLists.txt b/DesignPattern/CMakeLists.txt new file mode 100644 index 0000000..4fdbffe --- /dev/null +++ b/DesignPattern/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10) +project(DesignPattern) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(DesignPattern main.cpp AbstractFactoryPattern/product.h AbstractFactoryPattern/concrete_product.h AbstractFactoryPattern/Factory.cpp AbstractFactoryPattern/Factory.h AbstractFactoryPattern/concrete_factory.h AbstractFactoryPattern/FactoryMain.cpp AbstractFactoryPattern/FactoryMain.h SingletonPattern/Singleton.cpp SingletonPattern/Singleton.h SingletonPattern/SingletonMain.h AdapterPattern/target.h AdapterPattern/adaptee.h AdapterPattern/adapter.h AdapterPattern/AdapterMain.h BridgePattern/implementor.h BridgePattern/concrete_implementor.h BridgePattern/abstraction.h BridgePattern/refined_abstraction.h BridgePattern/BridgeMain.h BridgePattern/BridgeMain.cpp ObserverPattern/subject.h ObserverPattern/observer.h ObserverPattern/concrete_subject.h ObserverPattern/concrete_observer.h ObserverPattern/ObserverMain.cpp ObserverPattern/ObserverMain.h) \ No newline at end of file diff --git a/DesignPattern/ObserverPattern/ObserverMain.cpp b/DesignPattern/ObserverPattern/ObserverMain.cpp new file mode 100644 index 0000000..cd536c7 --- /dev/null +++ b/DesignPattern/ObserverPattern/ObserverMain.cpp @@ -0,0 +1,34 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#include "ObserverMain.h" + +void ObserverMain() +{ + // + ConcreteSubject * pSubject = new ConcreteSubject(); + + // ۲ + IObserver * pObserver1 = new ConcreteObserver("Jack Ma"); + IObserver * pObserver2 = new ConcreteObserver("Pony"); + + // ע۲ + pSubject->Attach(pObserver1); + pSubject->Attach(pObserver2); + + // ļ۸񣬲֪ͨ۲ + pSubject->SetPrice(12.5); + pSubject->Notify(); + + // עһ۲ + pSubject->Detach(pObserver2); + + // ٴθ״̬֪ͨ۲ + pSubject->SetPrice(15.0); + pSubject->Notify(); + + SAFE_DELETE(pObserver1); + SAFE_DELETE(pObserver2); + SAFE_DELETE(pSubject); +} \ No newline at end of file diff --git a/DesignPattern/ObserverPattern/ObserverMain.h b/DesignPattern/ObserverPattern/ObserverMain.h new file mode 100644 index 0000000..146c07c --- /dev/null +++ b/DesignPattern/ObserverPattern/ObserverMain.h @@ -0,0 +1,17 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_OBSERVERMAIN_H +#define DESIGNPATTERN_OBSERVERMAIN_H + +#include "concrete_subject.h" +#include "concrete_observer.h" + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} } +#endif + +void ObserverMain(); + +#endif //DESIGNPATTERN_OBSERVERMAIN_H diff --git a/DesignPattern/ObserverPattern/concrete_observer.h b/DesignPattern/ObserverPattern/concrete_observer.h new file mode 100644 index 0000000..37a68b3 --- /dev/null +++ b/DesignPattern/ObserverPattern/concrete_observer.h @@ -0,0 +1,25 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_CONCRETE_OBSERVER_H +#define DESIGNPATTERN_CONCRETE_OBSERVER_H + +#include "observer.h" +#include +#include + +class ConcreteObserver : public IObserver +{ +public: + ConcreteObserver(std::string name) { m_strName = name; } + void Update(float price) + { + std::cout << m_strName << " - price" << price << "\n"; + } + +private: + std::string m_strName; // 名字 +}; + +#endif //DESIGNPATTERN_CONCRETE_OBSERVER_H diff --git a/DesignPattern/ObserverPattern/concrete_subject.h b/DesignPattern/ObserverPattern/concrete_subject.h new file mode 100644 index 0000000..d05e98c --- /dev/null +++ b/DesignPattern/ObserverPattern/concrete_subject.h @@ -0,0 +1,45 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_CONCRETE_SUBJECT_H +#define DESIGNPATTERN_CONCRETE_SUBJECT_H + +#include "subject.h" +#include "observer.h" +#include +#include + +// 具体主题 +class ConcreteSubject : public ISubject +{ +public: + ConcreteSubject(){ m_fPrice = 10.0; } + void SetPrice(float price) + { + m_fPrice = price; + } + void Attach(IObserver * observer) + { + m_observers.push_back(observer); + } + void Detach(IObserver * observer) + { + m_observers.remove(observer); + } + // 通知所有观察者 + void Notify() + { + std::list::iterator it = m_observers.begin(); + while (it != m_observers.end()) + { + (*it)->Update(m_fPrice); + ++it; + } + } +private: + std::list m_observers; // 观察者列表 + float m_fPrice; // 价格 +}; + +#endif //DESIGNPATTERN_CONCRETE_SUBJECT_H diff --git a/DesignPattern/ObserverPattern/observer.h b/DesignPattern/ObserverPattern/observer.h new file mode 100644 index 0000000..500c396 --- /dev/null +++ b/DesignPattern/ObserverPattern/observer.h @@ -0,0 +1,15 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_OBSERVER_H +#define DESIGNPATTERN_OBSERVER_H + +// 抽象观察者 +class IObserver +{ +public: + virtual void Update(float price) = 0; // 更新价格 +}; + +#endif //DESIGNPATTERN_OBSERVER_H diff --git a/DesignPattern/ObserverPattern/subject.h b/DesignPattern/ObserverPattern/subject.h new file mode 100644 index 0000000..9d50fba --- /dev/null +++ b/DesignPattern/ObserverPattern/subject.h @@ -0,0 +1,18 @@ +// +// Created by xiemenghui on 2018/7/21. +// + +#ifndef DESIGNPATTERN_SUBJECT_H +#define DESIGNPATTERN_SUBJECT_H + +class IObserver; + +class ISubject +{ +public: + virtual void Attach(IObserver *) = 0; // 注册观察者 + virtual void Detach(IObserver *) = 0; // 注销观察者 + virtual void Notify() = 0; // 通知观察者 +}; + +#endif //DESIGNPATTERN_SUBJECT_H diff --git a/DesignPattern/README.md b/DesignPattern/README.md new file mode 100644 index 0000000..9adb480 --- /dev/null +++ b/DesignPattern/README.md @@ -0,0 +1,11 @@ +# 设计模式 + +> 各大设计模式例子参考:[CSDN专栏 . C++ 设计模式](https://blog.csdn.net/column/details/15392.html) 系列博文 + +此文件夹为一个 CLion 工程,由 CMake 构建,各个文件夹为各个设计模式的具体实现。文件中可能会有中文乱码问题,请以 `GB2312`(中文) 编码打开。 + +* [单例模式例子](SingletonPattern) +* [抽象工厂模式例子](AbstractFactoryPattern) +* [适配器模式例子](AdapterPattern) +* [桥接模式例子](BridgePattern) +* [观察者模式例子](ObserverPattern) \ No newline at end of file diff --git a/DesignPattern/SingletonPattern/README.md b/DesignPattern/SingletonPattern/README.md new file mode 100644 index 0000000..580b0b2 --- /dev/null +++ b/DesignPattern/SingletonPattern/README.md @@ -0,0 +1,34 @@ +# 单例模式 + +```cpp +// 懒汉式单例模式 +class Singleton +{ +private: + Singleton() { } + static Singleton * pInstance; +public: + static Singleton * GetInstance() + { + if (pInstance == nullptr) + pInstance = new Singleton(); + return pInstance; + } +}; + +// 线程安全的单例模式 +class Singleton +{ +private: + Singleton() { } + ~Singleton() { } + Singleton(const Singleton &); + Singleton & operator = (const Singleton &); +public: + static Singleton & GetInstance() + { + static Singleton instance; + return instance; + } +}; +``` \ No newline at end of file diff --git a/DesignPattern/SingletonPattern/Singleton.cpp b/DesignPattern/SingletonPattern/Singleton.cpp new file mode 100644 index 0000000..f090e53 --- /dev/null +++ b/DesignPattern/SingletonPattern/Singleton.cpp @@ -0,0 +1,11 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#include +#include "Singleton.h" + +void Singleton::DoSomething() +{ + std::cout << "Singleton do something\n"; +} \ No newline at end of file diff --git a/DesignPattern/SingletonPattern/Singleton.h b/DesignPattern/SingletonPattern/Singleton.h new file mode 100644 index 0000000..79bc8ad --- /dev/null +++ b/DesignPattern/SingletonPattern/Singleton.h @@ -0,0 +1,25 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_SINGLETON_H +#define DESIGNPATTERN_SINGLETON_H + +// 单例模式 +class Singleton { +private: + Singleton(){} + ~Singleton(){} + Singleton(const Singleton &); + Singleton & operator= (const Singleton &); + +public: + static Singleton & GetInstance() + { + static Singleton instance; + return instance; + } + void DoSomething(); +}; + +#endif //DESIGNPATTERN_SINGLETON_H diff --git a/DesignPattern/SingletonPattern/SingletonMain.h b/DesignPattern/SingletonPattern/SingletonMain.h new file mode 100644 index 0000000..673860f --- /dev/null +++ b/DesignPattern/SingletonPattern/SingletonMain.h @@ -0,0 +1,15 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#ifndef DESIGNPATTERN_SINGLETONMAIN_H +#define DESIGNPATTERN_SINGLETONMAIN_H + +#include "Singleton.h" + +void SingletonMain() +{ + Singleton::GetInstance().DoSomething(); +} + +#endif //DESIGNPATTERN_SINGLETONMAIN_H diff --git a/DesignPattern/main.cpp b/DesignPattern/main.cpp new file mode 100644 index 0000000..9e646ed --- /dev/null +++ b/DesignPattern/main.cpp @@ -0,0 +1,43 @@ +// +// Created by xiemenghui on 2018/7/20. +// + +#include +#include "SingletonPattern/SingletonMain.h" +#include "AbstractFactoryPattern/FactoryMain.h" +#include "AdapterPattern/AdapterMain.h" +#include "BridgePattern/BridgeMain.h" +#include "ObserverPattern/ObserverMain.h" + +int main() { + std::cout << "*******************" << std::endl; + std::cout << "** ģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + + std::cout << "*******************" << std::endl; + std::cout << "** ģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + SingletonMain(); + + std::cout << "*******************" << std::endl; + std::cout << "** 󹤳ģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + FactoryMain(); + + std::cout << "*******************" << std::endl; + std::cout << "** ģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + AdapterMain(); + + std::cout << "*******************" << std::endl; + std::cout << "** Žģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + BridgeMain(); + + std::cout << "*******************" << std::endl; + std::cout << "** ۲ģʽ **" << std::endl; + std::cout << "*******************" << std::endl; + ObserverMain(); + + return 0; +} \ No newline at end of file diff --git a/README.md b/README.md index 60975ea..1366d3b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # C/C++ 面试知识总结 -为 2018 年春招总结的 C/C++ 面试知识,只为复习、分享。部分知识点与图片来自网络,侵删。欢迎 star,欢迎 issues。 +C/C++ 面试知识总结,只为复习、分享。部分知识点与图片来自网络,侵删。 + +勘误请 Issue、Pull,新增请 Issue,建议、讨论请 [# issues/12](https://github.com/huihut/interview/issues/12) ## 使用建议 @@ -91,17 +93,6 @@ int* const function7(); // 返回一个指向变量的常指针,使用:i -### volatile - -```cpp -volatile int i = 10; -``` - -* volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。 -* volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值) -* const 可以是 volatile (如只读的状态寄存器) -* 指针可以是 volatile - ### static #### 作用 @@ -113,7 +104,7 @@ volatile int i = 10; ### this 指针 -1. `this` 指针是一个隐含于每一个成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。 +1. `this` 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。 2. 当对一个对象调用成员函数时,编译程序先将对象的地址赋给 `this` 指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含使用 `this` 指针。 3. 当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在的对象的指针。 4. `this` 指针被隐含地声明为: `ClassName *const this`,这意味着不能给 `this` 指针赋值;在 `ClassName` 类的 `const` 成员函数中,`this` 指针的类型为:`const ClassName* const`,这说明不能对 `this` 指针所指向的这种对象是不可修改的(即不能对这种对象的数据成员进行赋值操作); @@ -151,7 +142,7 @@ inline int functionName(int first, int secend,...) {/****/}; -#### 编译器对inline函数的处理步骤 +#### 编译器对 inline 函数的处理步骤 1. 将 inline 函数体复制到 inline 函数调用点处; 2. 为所用 inline 函数中的局部变量分配内存空间; @@ -228,9 +219,7 @@ int main() ### assert() -断言,是宏,而非函数。assert 宏的原型定义在``(C)、``(C++)中,其作用是如果它的条件返回错误,则终止程序执行。 - -如 +断言,是宏,而非函数。assert 宏的原型定义在``(C)、``(C++)中,其作用是如果它的条件返回错误,则终止程序执行。如: ```cpp assert( p != NULL ); @@ -264,6 +253,29 @@ struct test +### 位域 + +```cpp +Bit mode: 2; // mode 占 2 位 +``` + +类可以将其(非静态)数据成员定义为位域(bit-field),在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或硬件设备传递二进制数据时,通常会用到位域。 + +* 位域在内存中的布局是与机器有关的 +* 位域的类型必须是整型或枚举类型,带符号类型中的位域的行为将因具体实现而定 +* 取地址运算符(&)不能作用于位域,任何指针都无法指向类的位域 + +### volatile + +```cpp +volatile int i = 10; +``` + +* volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。 +* volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值) +* const 可以是 volatile (如只读的状态寄存器) +* 指针可以是 volatile + ### extern "C" * 被 extern 限定的函数或变量是 extern 类型的 @@ -358,6 +370,57 @@ int main() { 1. 默认的继承访问权限。struct 是 public 的,class 是 private 的。 2. struct 作为数据结构的实现体,它默认的数据访问控制是 public 的,而 class 作为对象的实现体,它默认的成员变量访问控制是 private 的。 +### union 联合 + +联合(union)是一种节省空间的特殊的类,一个 union 可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当某个成员被赋值后其他成员变为未定义状态。联合有如下特点: + +* 默认访问控制符为 public +* 可以含有构造函数、析构函数 +* 不能含有引用类型的成员 +* 不能继承自其他类,不能作为基类 +* 不能含有虚函数 +* 匿名 union 在定义所在作用域可直接访问 union 成员 +* 匿名 union 不能包含 protected 成员或 private 成员 +* 全局匿名联合必须是静态(static)的 + +
union 使用 + +```cpp +#include + +union UnionTest { + UnionTest() : i(10) {}; + int i; + double d; +}; + +static union { + int i; + double d; +}; + +int main() { + UnionTest u; + + union { + int i; + double d; + }; + + std::cout << u.i << std::endl; // 输出 UnionTest 联合的 10 + + ::i = 20; + std::cout << ::i << std::endl; // 输出全局静态匿名联合的 20 + + i = 30; + std::cout << i << std::endl; // 输出局部匿名联合的 30 + + return 0; +} +``` + +
+ ### C 实现 C++ 类 [C 语言实现封装、继承和多态](http://dongxicheng.org/cpp/ooc/) @@ -420,6 +483,24 @@ int main() using namespace_name::name; ``` +#### 构造函数的 using 声明【C++11】 + +在 C++11 中,派生类能够重用其直接基类定义的构造函数。 + +```cpp +class Derived : Base { +public: + using Base::Base; + /* ... */ +}; +``` + +如上 using 声明,对于基类的每个构造函数,编译器都生成一个与之对应(形参列表完全相同)的派生类构造函数。生成如下类型构造函数: + +```cpp +derived(parms) : base(args) { } +``` + #### using 指示 `using 指示` 使得某个特定命名空间中所有名字都可见,这样我们就无需再为它们添加任何前缀限定符了。如: @@ -472,17 +553,17 @@ cout << x << endl;
:: 使用 ```cpp -int count = 0; // 全局(::)的 count +int count = 0; // 全局(::)的 count class A { public: - static int count; // 类 A 的 count(A::count) + static int count; // 类 A 的 count(A::count) }; int main() { ::count = 1; // 设置全局的 count 的值为 1 - A::count = 2; // 设置类 A 的 count 为 2 + A::count = 2; // 设置类 A 的 count 为 2 int count = 0; // 局部的 count count = 3; // 设置局部的 count 的值为 3 @@ -493,11 +574,75 @@ int main() {
+### enum 枚举类型 + +#### 限定作用域的枚举类型 + +```cpp +enum class open_modes { input, output, append }; +``` + +#### 不限定作用域的枚举类型 + +```cpp +enum color { red, yellow, green }; +enum { floatPrec = 6, doublePrec = 10 }; +``` + +### decltype + +decltype 关键字用于检查实体的声明类型或表达式的类型及值分类。语法: + +```cpp +decltype ( expression ) +``` + +
decltype 使用 + +```cpp +// 尾置返回允许我们在参数列表之后声明返回类型 +template +auto fcn(It beg, It end) -> decltype(*beg) +{ + // 处理序列 + return *beg; // 返回序列中一个元素的引用 +} +// 为了使用模板参数成员,必须用 typename +template +auto fcn2(It beg, It end) -> typename remove_reference::type +{ + // 处理序列 + return *beg; // 返回序列中一个元素的拷贝 +} +``` + +
+ +### 引用 + +#### 左值引用 + +常规引用,一般表示对象的身份。 + +#### 右值引用 + +右值引用就是必须绑定到右值(一个临时对象、将要销毁的对象)的引用,一般表示对象的值。 + +右值引用可实现转移语义(Move Sementics)和精确传递(Perfect Forwarding),它的主要目的有两个方面: + +* 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。 +* 能够更简洁明确地定义泛型函数。 + +#### 引用折叠 + +* `X& &`、`X& &&`、`X&& &` 可折叠成 `X&` +* `X&& &&` 可折叠成 `X&&` + ### 宏 -* 宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对 “参数” 进行的是一对一的替换。 +* 宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对 “参数” 进行的是一对一的替换。 -### 初始化列表 +### 成员初始化列表 好处 @@ -507,6 +652,64 @@ int main() { 2. 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面 3. 没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。 +### initializer_list 列表初始化【C++11】 + +用花括号初始化器列表列表初始化一个对象,其中对应构造函数接受一个 `std::initializer_list` 参数. + +
initializer_list 使用 + +```cpp +#include +#include +#include + +template +struct S { + std::vector v; + S(std::initializer_list l) : v(l) { + std::cout << "constructed with a " << l.size() << "-element list\n"; + } + void append(std::initializer_list l) { + v.insert(v.end(), l.begin(), l.end()); + } + std::pair c_arr() const { + return {&v[0], v.size()}; // 在 return 语句中复制列表初始化 + // 这不使用 std::initializer_list + } +}; + +template +void templated_fn(T) {} + +int main() +{ + S s = {1, 2, 3, 4, 5}; // 复制初始化 + s.append({6, 7, 8}); // 函数调用中的列表初始化 + + std::cout << "The vector size is now " << s.c_arr().second << " ints:\n"; + + for (auto n : s.v) + std::cout << n << ' '; + std::cout << '\n'; + + std::cout << "Range-for over brace-init-list: \n"; + + for (int x : {-1, -2, -3}) // auto 的规则令此带范围 for 工作 + std::cout << x << ' '; + std::cout << '\n'; + + auto al = {10, 11, 12}; // auto 的特殊规则 + + std::cout << "The list bound to auto has size() = " << al.size() << '\n'; + +// templated_fn({1, 2, 3}); // 编译错误!“ {1, 2, 3} ”不是表达式, + // 它无类型,故 T 无法推导 + templated_fn>({1, 2, 3}); // OK + templated_fn>({1, 2, 3}); // 也 OK +} +``` + +
### 面向对象 @@ -675,6 +878,11 @@ virtual int A() = 0; * 虚函数不占用存储空间 * 虚函数表存储的是虚函数地址 +### 模板类、成员模板、虚函数 + +* 模板类中可以使用虚函数 +* 一个类(无论是普通类还是类模板)的成员模板(本身是模板的成员函数)不能是虚函数 + ### 抽象类、接口类、聚合类 * 抽象类:含有纯虚函数的类 @@ -718,7 +926,7 @@ p = nullptr; #### new、delete -1. new/new[]:完成两件事,先底层调用 malloc 分了配内存,然后调用构造函数(创建对象)。 +1. new / new[]:完成两件事,先底层调用 malloc 分了配内存,然后调用构造函数(创建对象)。 2. delete/delete[]:也完成两件事,先调用析构函数(清理资源),然后底层调用 free 释放空间。 3. new 在申请内存时会自动计算所需字节数,而 malloc 则需我们自己输入申请内存空间的字节数。 @@ -737,6 +945,20 @@ int main() +#### 定位 new + +定位 new(placement new)允许我们向 new 传递额外的参数。 + +```cpp +new (palce_address) type +new (palce_address) type (initializers) +new (palce_address) type [size] +new (palce_address) type [size] { braced initializer list } +``` + +* `palce_address` 是个指针 +* `initializers` 提供一个(可能为空的)以逗号分隔的初始值列表 + ### delete this 合法吗? [Is it legal (and moral) for a member function to say delete this?](https://isocpp.org/wiki/faq/freestore-mgmt#delete-this) @@ -1004,11 +1226,6 @@ hash_multiset|hash表|无序|可重复| hash_map|hash表|无序|不可重复| hash_multimap|hash表|无序|可重复| -### STL 空间配置器如何处理内存的?能说一下它的大概实现方案吗?为什么是 8Bytes 的倍数? - -* 大于 128Bytes 用 malloc 直接申请 -* 小于 128Bytes 使用一个 8Bytes 倍数的数组来进行申请(原因是为了提高效率,同时对于 64 位的机器而言,地址大小为 8Bytes) - ## 数据结构 ### 顺序结构 @@ -1478,6 +1695,21 @@ typedef struct BiTNode 2-3树 | O(log2n - log3n) | | B树/B+树 |O(log2n) | | +### 图搜索算法 + +图搜索算法 |数据结构| 遍历时间复杂度 | 空间复杂度 +---|---|---|--- +[BFS广度优先搜索](https://zh.wikipedia.org/wiki/%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2)|邻接矩阵
邻接链表|O(\|v\|2)
O(\|v\|+\|E\|)|O(\|v\|2)
O(\|v\|+\|E\|) +[DFS深度优先搜索](https://zh.wikipedia.org/wiki/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2)|邻接矩阵
邻接链表|O(\|v\|2)
O(\|v\|+\|E\|)|O(\|v\|2)
O(\|v\|+\|E\|) + +### 其他算法 + +算法 |思想| 应用 +---|---|--- +[分治法](https://zh.wikipedia.org/wiki/%E5%88%86%E6%B2%BB%E6%B3%95)|把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并|[循环赛日程安排问题](https://github.com/huihut/interview/tree/master/Problems/RoundRobinProblem)、排序算法(快速排序、归并排序) +[动态规划](https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92)|通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法,适用于有重叠子问题和最优子结构性质的问题|[背包问题](https://github.com/huihut/interview/tree/master/Problems/KnapsackProblem)、斐波那契数列 +[贪心法](https://zh.wikipedia.org/wiki/%E8%B4%AA%E5%BF%83%E6%B3%95)|一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法|旅行推销员问题(最短路径问题)、最小生成树、哈夫曼编码 + ## Problems ### Single Problem @@ -1962,6 +2194,41 @@ TCP 是一个基于字节流的传输服务(UDP 基于报文的),“流” * 在数据包之间设置边界,如添加特殊符号 `\r\n` 标记。FTP 协议正是这么做的。但问题在于如果数据正文中也含有 `\r\n`,则会误判为消息的边界。 * 使用更加复杂的应用层协议。 +#### TCP 流量控制 + +##### 概念 + +流量控制(flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收。 + +##### 方法 + +
利用可变窗口进行流量控制 + +![](images/利用可变窗口进行流量控制举例.png) + +
+ +#### TCP 拥塞控制 + +##### 概念 + +拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。 + +##### 方法 + +* 慢开始( slow-start ) +* 拥塞避免( congestion avoidance ) +* 快重传( fast retransmit ) +* 快恢复( fast recovery ) + +
TCP的拥塞控制图 + +![](images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png) +![](images/快重传示意图.png) +![](images/TCP的拥塞控制流程图.png) + +
+ #### TCP 传输连接管理 > 因为 TCP 三次握手建立连接、四次挥手释放连接很重要,所以附上《计算机网络(第 7 版)-谢希仁》书中对此章的详细描述: @@ -2200,6 +2467,30 @@ ssize_t write(int fd, const void *buf, size_t count); ## 设计模式 +> 各大设计模式例子参考:[CSDN专栏 . C++ 设计模式](https://blog.csdn.net/column/details/15392.html) 系列博文 + +[设计模式工程目录](DesignPattern) + +### 单例模式 + +[单例模式例子](DesignPattern/SingletonPattern) + +### 抽象工厂模式 + +[抽象工厂模式例子](DesignPattern/AbstractFactoryPattern) + +### 适配器模式 + +[适配器模式例子](DesignPattern/AdapterPattern) + +### 桥接模式 + +[桥接模式例子](DesignPattern/BridgePattern) + +### 观察者模式 + +[观察者模式例子](DesignPattern/ObserverPattern) + ### 设计模式的六大原则 * 单一职责原则(SRP,Single Responsibility Principle) @@ -2209,41 +2500,6 @@ ssize_t write(int fd, const void *buf, size_t count); * 迪米特法则(LoD,Law of Demeter) * 开放封闭原则(OCP,Open Close Principle) -### 单例模式 - -```cpp -// 懒汉式单例模式 -class Singleton -{ -private: - Singleton() { } - static Singleton * pInstance; -public: - static Singleton * GetInstance() - { - if (pInstance == nullptr) - pInstance = new Singleton(); - return pInstance; - } -}; - -// 线程安全的单例模式 -class Singleton -{ -private: - Singleton() { } - ~Singleton() { } - Singleton(const Singleton &); - Singleton & operator = (const Singleton &); -public: - static Singleton & GetInstance() - { - static Singleton instance; - return instance; - } -}; -``` - ## 链接装载库 ### 内存、栈、堆 @@ -2282,6 +2538,14 @@ public: ### 编译链接 +#### 各平台文件格式 + +平台 | 可执行文件 | 目标文件 | 动态库/共享对象 | 静态库 +---|---|---|---|--- +Windows|exe|obj|dll|lib +Unix/Linux|ELF、out|o|so|a +Mac|Mach-O|o|dylib、tbd、framework|a、framework + #### 编译链接过程 1. 预编译(预编译器处理如 `#include`、`#define` 等预编译指令,生成 `.i` 或 `.ii` 文件) @@ -2365,41 +2629,379 @@ Linux 下的共享库就是普通的 ELF 共享对象。 * `LD_PRELOAD`:指定预先装载的一些共享库甚至是目标文件 * `LD_DEBUG`:打开动态链接器的调试功能 -### Windows 的动态链接库(Dynamic-Link Library) +#### so 共享库的编写 -
Windows 动态链接库例子 +
使用 CLion 编写共享库 + +创建一个名为 MySharedLib 的共享库 + +CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.10) +project(MySharedLib) + +set(CMAKE_CXX_STANDARD 11) + +add_library(MySharedLib SHARED library.cpp library.h) +``` + +library.h -DLL 头文件 ```cpp -#ifdef __cplusplus -extern "C" { -#endif +#ifndef MYSHAREDLIB_LIBRARY_H +#define MYSHAREDLIB_LIBRARY_H -#ifdef _WIN32 -# ifdef MODULE_API_EXPORTS -# define MODULE_API __declspec(dllexport) -# else -# define MODULE_API __declspec(dllimport) -# endif -#else -# define MODULE_API -#endif +// 打印 Hello World! +void hello(); -MODULE_API int module_init(); - -#ifdef __cplusplus +// 使用可变模版参数求和 +template +T sum(T t) +{ + return t; } +template +T sum(T first, Types ... rest) +{ + return first + sum(rest...); +} + #endif ``` -DLL 源文件 -```cpp -#define MODULE_API_EXPORTS -#include "module.h" +library.cpp -MODULE_API int module_init() +```cpp +#include +#include "library.h" + +void hello() { + std::cout << "Hello, World!" << std::endl; +} +``` + +
+ +#### so 共享库的使用(被可执行项目调用) + +
使用 CLion 调用共享库 + +创建一个名为 TestSharedLib 的可执行项目 + +CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.10) +project(TestSharedLib) + +# C++11 编译 +set(CMAKE_CXX_STANDARD 11) + +# 头文件路径 +set(INC_DIR /home/xx/code/clion/MySharedLib) +# 库文件路径 +set(LIB_DIR /home/xx/code/clion/MySharedLib/cmake-build-debug) + +include_directories(${INC_DIR}) +link_directories(${LIB_DIR}) +link_libraries(MySharedLib) + +add_executable(TestSharedLib main.cpp) + +# 链接 MySharedLib 库 +target_link_libraries(TestSharedLib MySharedLib) +``` + +main.cpp + +```cpp +#include +#include "library.h" +using std::cout; +using std::endl; + +int main() { + + hello(); + cout << "1 + 2 = " << sum(1,2) << endl; + cout << "1 + 2 + 3 = " << sum(1,2,3) << endl; + + return 0; +} +``` + +执行结果 + +``` +Hello, World! +1 + 2 = 3 +1 + 2 + 3 = 6 +``` + +
+ +### Windows 应用程序入口函数 + +* GUI(Graphical User Interface)应用,链接器选项:`/SUBSYSTEM:WINDOWS` +* CUI(Console User Interface)应用,链接器选项:`/SUBSYSTEM:CONSOLE` + +
_tWinMain 与 _tmain 函数声明 + +```cpp +Int WINAPI _tWinMain( + HINSTANCE hInstanceExe, + HINSTANCE, + PTSTR pszCmdLine, + int nCmdShow); + +int _tmain( + int argc, + TCHAR *argv[], + TCHAR *envp[]); +``` + +
+ +应用程序类型|入口点函数|嵌入可执行文件的启动函数 +---|---|--- +处理ANSI字符(串)的GUI应用程序|_tWinMain(WinMain)|WinMainCRTSartup +处理Unicode字符(串)的GUI应用程序|_tWinMain(wWinMain)|wWinMainCRTSartup +处理ANSI字符(串)的CUI应用程序|_tmain(Main)|mainCRTSartup +处理Unicode字符(串)的CUI应用程序|_tmain(wMain)|wmainCRTSartup +动态链接库(Dynamic-Link Library)|DllMain|_DllMainCRTStartup + +### Windows 的动态链接库(Dynamic-Link Library) + +> 知识点来自《Windows核心编程(第五版)》 + +#### 用处 + +* 扩展了应用程序的特性 +* 简化了项目管理 +* 有助于节省内存 +* 促进了资源的共享 +* 促进了本地化 +* 有助于解决平台间的差异 +* 可以用于特殊目的 + +#### 注意 + +* 创建 DLL,事实上是在创建可供一个可执行模块调用的函数 +* 当一个模块提供一个内存分配函数(malloc、new)的时候,它必须同时提供另一个内存释放函数(free、delete) +* 在使用 C 和 C++ 混编的时候,要使用 extern "C" 修饰符 +* 一个 DLL 可以导出函数、变量(避免导出)、C++ 类(导出导入需要同编译器,否则避免导出) +* DLL 模块:cpp 文件中的 __declspec(dllexport) 写在 include 头文件之前 +* 调用 DLL 的可执行模块:cpp 文件的 __declspec(dllimport) 之前不应该定义 MYLIBAPI + +#### 加载 Windows 程序的搜索顺序 + +1. 包含可执行文件的目录 +2. Windows 的系统目录,可以通过 GetSystemDirectory 得到 +3. 16 位的系统目录,即 Windows 目录中的 System 子目录 +4. Windows 目录,可以通过 GetWindowsDirectory 得到 +5. 进程的当前目录 +6. PATH 环境变量中所列出的目录 + +#### DLL 入口函数 + +
DllMain 函数 + +```cpp +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - /* do something useful */ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + // 第一次将一个DLL映射到进程地址空间时调用 + // The DLL is being mapped into the process' address space. + break; + case DLL_THREAD_ATTACH: + // 当进程创建一个线程的时候,用于告诉DLL执行与线程相关的初始化(非主线程执行) + // A thread is bing created. + break; + case DLL_THREAD_DETACH: + // 系统调用 ExitThread 线程退出前,即将终止的线程通过告诉DLL执行与线程相关的清理 + // A thread is exiting cleanly. + break; + case DLL_PROCESS_DETACH: + // 将一个DLL从进程的地址空间时调用 + // The DLL is being unmapped from the process' address space. + break; + } + return (TRUE); // Used only for DLL_PROCESS_ATTACH +} +``` + +
+ +#### 载入卸载库 + +
LoadLibrary、LoadLibraryExA、LoadPackagedLibrary、FreeLibrary、FreeLibraryAndExitThread 函数声明 + +```cpp +// 载入库 +HMODULE WINAPI LoadLibrary( + _In_ LPCTSTR lpFileName +); +HMODULE LoadLibraryExA( + LPCSTR lpLibFileName, + HANDLE hFile, + DWORD dwFlags +); +// 若要在通用 Windows 平台(UWP)应用中加载 Win32 DLL,需要调用 LoadPackagedLibrary,而不是 LoadLibrary 或 LoadLibraryEx +HMODULE LoadPackagedLibrary( + LPCWSTR lpwLibFileName, + DWORD Reserved +); + +// 卸载库 +BOOL WINAPI FreeLibrary( + _In_ HMODULE hModule +); +// 卸载库和退出线程 +VOID WINAPI FreeLibraryAndExitThread( + _In_ HMODULE hModule, + _In_ DWORD dwExitCode +); +``` + +
+ +#### 显示地链接到导出符号 + +
GetProcAddress 函数声明 + +```cpp +FARPROC GetProcAddress( + HMODULE hInstDll, + PCSTR pszSymbolName // 只能接受 ANSI 字符串,不能是 Unicode +); +``` + +
+ +#### DumpBin.exe 查看 DLL 信息 + +在 `VS 的开发人员命令提示符` 使用 `DumpBin.exe` 可查看 DLL 库的导出段(导出的变量、函数、类名的符号)、相对虚拟地址(RVA,relative virtual address)。如: +``` +DUMPBIN -exports D:\mydll.dll +``` + +#### LoadLibrary 与 FreeLibrary 流程图 + +
LoadLibrary 与 FreeLibrary 流程图 + +##### LoadLibrary + +![WindowsLoadLibrary](http://ojlsgreog.bkt.clouddn.com/WindowsLoadLibrary.png) + +##### FreeLibrary + +![WindowsFreeLibrary](http://ojlsgreog.bkt.clouddn.com/WindowsFreeLibrary.png) + +
+ +#### DLL 库的编写(导出一个 DLL 模块) + +
DLL 库的编写(导出一个 DLL 模块) +DLL 头文件 + +```cpp +// MyLib.h + +#ifdef MYLIBAPI + +// MYLIBAPI 应该在全部 DLL 源文件的 include "Mylib.h" 之前被定义 +// 全部函数/变量正在被导出 + +#else + +// 这个头文件被一个exe源代码模块包含,意味着全部函数/变量被导入 +#define MYLIBAPI extern "C" __declspec(dllimport) + +#endif + +// 这里定义任何的数据结构和符号 + +// 定义导出的变量(避免导出变量) +MYLIBAPI int g_nResult; + +// 定义导出函数原型 +MYLIBAPI int Add(int nLeft, int nRight); +``` + +DLL 源文件 + +```cpp +// MyLibFile1.cpp + +// 包含标准Windows和C运行时头文件 +#include + +// DLL源码文件导出的函数和变量 +#define MYLIBAPI extern "C" __declspec(dllexport) + +// 包含导出的数据结构、符号、函数、变量 +#include "MyLib.h" + +// 将此DLL源代码文件的代码放在此处 +int g_nResult; + +int Add(int nLeft, int nRight) +{ + g_nResult = nLeft + nRight; + return g_nResult; +} +``` + +
+ +#### DLL 库的使用(运行时动态链接 DLL) + +
DLL 库的使用(运行时动态链接 DLL) + +```cpp +// A simple program that uses LoadLibrary and +// GetProcAddress to access myPuts from Myputs.dll. + +#include +#include + +typedef int (__cdecl *MYPROC)(LPWSTR); + +int main( void ) +{ + HINSTANCE hinstLib; + MYPROC ProcAdd; + BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; + + // Get a handle to the DLL module. + + hinstLib = LoadLibrary(TEXT("MyPuts.dll")); + + // If the handle is valid, try to get the function address. + + if (hinstLib != NULL) + { + ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts"); + + // If the function address is valid, call the function. + + if (NULL != ProcAdd) + { + fRunTimeLinkSuccess = TRUE; + (ProcAdd) (L"Message sent to the DLL function\n"); + } + // Free the DLL module. + + fFreeResult = FreeLibrary(hinstLib); + } + + // If unable to call the DLL function, use an alternative. + if (! fRunTimeLinkSuccess) + printf("Message printed from executable\n"); + return 0; } ``` @@ -2521,7 +3123,7 @@ MODULE_API int module_init() ## 招聘时间岗位 -* [牛客网 . 2018 IT名企校招指南](https://www.nowcoder.com/activity/campus2018) +* [牛客网 . 2019 IT名企校招指南](https://www.nowcoder.com/activity/campus2019) ## 面试题目经验 diff --git a/STL/README.md b/STL/README.md index f1e5430..1d84846 100644 --- a/STL/README.md +++ b/STL/README.md @@ -54,7 +54,7 @@ empty|返回 vector 是否为空 reserve|请求 vector 容量至少足以包含 n(参数)个元素 shrink_to_fit|要求容器减小其 capacity(容量)以适应其 size(元素数量) operator[]|返回容器中第 n(参数)个位置的元素的引用 -at|返回中第 n(参数)个位置的元素的引用 +at|返回容器中第 n(参数)个位置的元素的引用 front|返回对容器中第一个元素的引用 back|返回对容器中最后一个元素的引用 data|返回指向容器中第一个元素的指针 @@ -183,10 +183,10 @@ equal(beg1, end1, beg2); // 比较每个元素,确定两个序列是否相等 equal(beg1, end1, beg2, binaryPred); // 比较每个元素,确定两个序列是否相等。 // 二分搜索算法,传入前向迭代器或随机访问迭代器(random-access iterator),要求序列中的元素已经是有序的。通过小于运算符(<)或 comp 比较操作实现比较。 -lower_bound(beg, end, val); // 返回一个迭代器,表示第一个小于等于 val 的元素,不存在则返回 end -lower_bound(beg, end, val, comp); // 返回一个迭代器,表示第一个小于等于 val 的元素,不存在则返回 end -upper_bound(beg, end, val); // 返回一个迭代器,表示第一个大于 val 的元素,不存在则返回 end -upper_bound(beg, end, val, comp); // 返回一个迭代器,表示第一个大于 val 的元素,不存在则返回 end +lower_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end +lower_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end +upper_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end +upper_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end equal_range(beg, end, val); // 返回一个 pair,其 first 成员是 lower_bound 返回的迭代器,其 second 成员是 upper_bound 返回的迭代器 binary_search(beg, end, val); // 返回一个 bool 值,指出序列中是否包含等于 val 的元素。对于两个值 x 和 y,当 x 不小于 y 且 y 也不小于 x 时,认为它们相等。 @@ -206,7 +206,7 @@ transform(beg, end, beg2, dest, binaryOp); // 调用给定操作(二元操作 replace_copy(beg, end, dest, old_val, new_val); // 将每个元素拷贝到 dest,将等于 old_val 的的元素替换为 new_val replace_copy_if(beg, end, dest, unaryPred, new_val); // 将每个元素拷贝到 dest,将满足 unaryPred 的的元素替换为 new_val merge(beg1, end1, beg2, end2, dest); // 两个输入序列必须都是有序的,用 < 运算符将合并后的序列写入到 dest 中 -merge(beg1, end1, beg2, end2, dest, comp) // 两个输入序列必须都是有序的,使用给定的比较操作(comp)将合并后的序列写入到 dest 中 +merge(beg1, end1, beg2, end2, dest, comp); // 两个输入序列必须都是有序的,使用给定的比较操作(comp)将合并后的序列写入到 dest 中 // 使用前向迭代器的写算法,要求前向迭代器 iter_swap(iter1, iter2); // 交换 iter1 和 iter2 所表示的元素,返回 void @@ -218,7 +218,7 @@ replace_if(beg, end, unaryPred, new_val); // 用 new_val 替换满足 unaryPred copy_backward(beg, end, dest); // 从输入范围中拷贝元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。 move_backward(beg, end, dest); // 从输入范围中移动元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。 inplace_merge(beg, mid, end); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用 < 比较元素。 -inplace_merge(beg, mid, end, comp) // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。 +inplace_merge(beg, mid, end, comp); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。 // 划分算法,要求双向选代器(bidirectional iterator) is_partitioned(beg, end, unaryPred); // 如果所有满足谓词 unaryPred 的元素都在不满足 unarypred 的元素之前,则返回 true。若序列为空,也返回 true @@ -230,8 +230,8 @@ partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足 // 排序算法,要求随机访问迭代器(random-access iterator) sort(beg, end); // 排序整个范围 stable_sort(beg, end); // 排序整个范围(稳定排序) -sort(beg, end, comp) // 排序整个范围 -stable_sort(beg, end, comp) // 排序整个范围(稳定排序) +sort(beg, end, comp); // 排序整个范围 +stable_sort(beg, end, comp); // 排序整个范围(稳定排序) is_sorted(beg, end); // 返回一个 bool 值,指出整个输入序列是否有序 is_sorted(beg, end, comp); // 返回一个 bool 值,指出整个输入序列是否有序 is_sorted_until(beg, end); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器 diff --git a/STL/STL.md b/STL/STL.md index 73de734..4deb632 100644 --- a/STL/STL.md +++ b/STL/STL.md @@ -35,7 +35,7 @@ array是固定大小的顺序容器,它们保存了一个以严格的线性顺 数组容器的另一个独特特性是它们可以被当作元组对象来处理:array头部重载get函数来访问数组元素,就像它是一个元组,以及专门的tuple_size和tuple_element类型。 -``` +```cpp template < class T, size_t N > class array; ``` @@ -47,14 +47,14 @@ template < class T, size_t N > class array; ![](https://i.stack.imgur.com/oa3EQ.png) -``` +```cpp iterator begin() noexcept; const_iterator begin() const noexcept; ``` Example -``` +```cpp #include #include @@ -78,14 +78,14 @@ myarray contains: 2 16 77 34 50 返回指向数组容器中最后一个元素之后的理论元素的迭代器。 -``` +```cpp iterator end() noexcept; const_iterator end() const noexcept; ``` Example -``` +```cpp #include #include @@ -111,12 +111,12 @@ myarray contains: 5 19 77 34 99 返回指向数组容器中最后一个元素的反向迭代器。 -``` +```cpp reverse_iterator rbegin()noexcept; const_reverse_iterator rbegin()const noexcept; ``` Example -``` +```cpp #include #include @@ -140,13 +140,13 @@ myarray contains: 14 80 26 4 返回一个反向迭代器,指向数组中第一个元素之前的理论元素(这被认为是它的反向结束)。 -``` +```cpp reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; ``` Example -``` +```cpp #include #include @@ -170,11 +170,11 @@ myarray contains: 14 80 26 4 #### array::cbegin 返回指向数组容器中第一个元素的常量迭代器(const_iterator);这个迭代器可以增加和减少,但是不能用来修改它指向的内容。 -``` +```cpp const_iterator cbegin()const noexcept; ``` Example -``` +```cpp #include #include @@ -199,11 +199,11 @@ myarray contains: 2 16 77 34 50 #### array::cend 返回指向数组容器中最后一个元素之后的理论元素的常量迭代器(const_iterator)。这个迭代器可以增加和减少,但是不能用来修改它指向的内容。 -``` +```cpp const_iterator cend() const noexcept; ``` Example -``` +```cpp #include #include @@ -227,11 +227,11 @@ myarray contains: 2 16 77 34 50 #### array::crbegin 返回指向数组容器中最后一个元素的常量反向迭代器(const_reverse_iterator) -``` +```cpp const_reverse_iterator crbegin()const noexcept; ``` Example -``` +```cpp #include #include @@ -256,11 +256,11 @@ myarray backwards: 60 50 40 30 20 10 返回指向数组中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator),它被认为是其反向结束。 -``` +```cpp const_reverse_iterator crend() const noexcept; ``` Example -``` +```cpp #include #include @@ -286,11 +286,11 @@ myarray backwards: 60 50 40 30 20 10 返回数组容器中元素的数量。 -``` +```cpp constexpr size_type size()noexcept; ``` Example -``` +```cpp #include #include @@ -310,11 +310,11 @@ sizeof(myints): 20 ``` #### array::max_size 返回数组容器可容纳的最大元素数。数组对象的max_size与其size一样,始终等于用于实例化数组模板类的第二个模板参数。 -``` +```cpp constexpr size_type max_size() noexcept; ``` Example -``` +```cpp #include #include @@ -335,11 +335,11 @@ max_size of myints: 10 #### array::empty 返回一个布尔值,指示数组容器是否为空,即它的size()是否为0。 -``` +```cpp constexpr bool empty() noexcept; ``` Example -``` +```cpp #include #include @@ -359,12 +359,12 @@ second is not empt ``` #### array::operator[] 返回数组中第n个位置的元素的引用。与array::at相似,但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围,而array::operator[]不检查边界。 -``` +```cpp reference operator[] (size_type n); const_reference operator[] (size_type n) const; ``` Example -``` +```cpp #include #include @@ -392,12 +392,12 @@ myarray contains: 0 1 2 3 4 5 6 7 8 9 ``` #### array::at 返回数组中第n个位置的元素的引用。与array::operator[]相似,但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围,而array::operator[]不检查边界。 -``` +```cpp reference at ( size_type n ); const_reference at ( size_type n ) const; ``` Example -``` +```cpp #include #include @@ -426,12 +426,12 @@ myarray contains: 0 1 2 3 4 5 6 7 8 9 #### array::front 返回对数组容器中第一个元素的引用。array::begin返回的是迭代器,array::front返回的是直接引用。 在空容器上调用此函数会导致未定义的行为。 -``` +```cpp reference front(); const_reference front() const; ``` Example -``` +```cpp #include #include @@ -461,12 +461,12 @@ myarray now contains: 100 16 77 #### array::back 返回对数组容器中最后一个元素的引用。array::end返回的是迭代器,array::back返回的是直接引用。 在空容器上调用此函数会导致未定义的行为。 -``` +```cpp reference back(); const_reference back() const; ``` Example -``` +```cpp #include #include @@ -496,12 +496,12 @@ myarray now contains: 5 19 50 返回指向数组对象中第一个元素的指针。 由于数组中的元素存储在连续的存储位置,所以检索到的指针可以偏移以访问数组中的任何元素。 -``` +```cpp value_type* data() noexcept; const value_type* data() const noexcept; ``` Example -``` +```cpp #include #include #include @@ -524,11 +524,11 @@ Test string ``` #### array::fill 用val填充数组所有元素,将val设置为数组对象中所有元素的值。 -``` +```cpp void fill (const value_type& val); ``` Example -``` +```cpp #include #include @@ -553,11 +553,11 @@ myarray contains: 5 5 5 5 5 5 通过x的内容交换数组的内容,这是另一个相同类型的数组对象(包括相同的大小)。 与其他容器的交换成员函数不同,此成员函数通过在各个元素之间执行与其大小相同的单独交换操作,以线性时间运行。 -``` +```cpp void swap (array& x) noexcept(noexcept(swap(declval(),declval()))); ``` Example -``` +```cpp #include #include @@ -586,13 +586,13 @@ second: 10 20 30 40 50 ``` #### get(array) 形如:std::get<0>(myarray);传入一个数组容器,返回指定位置元素的引用。 -``` +```cpp template T&get(array &arr)noexcept; template T && get(array && arr)noexcept; template const T&get(const array &arr)noexcept; ``` Example -``` +```cpp #include #include #include @@ -621,7 +621,7 @@ first element in mytuple: 10 ``` #### relational operators (array) 形如:arrayA != arrayB、arrayA > arrayB;依此比较数组每个元素的大小关系。 -``` +```cpp (1) template bool operator ==(const array &lhs,const array &rhs); @@ -642,7 +642,7 @@ template bool operator> =(const array &lhs,const array &rhs); ``` Example -``` +```cpp #include #include @@ -680,7 +680,7 @@ vector是表示可以改变大小的数组的序列容器。 相反,vector容器可以分配一些额外的存储以适应可能的增长,并且因此容器可以具有比严格需要包含其元素(即,其大小)的存储更大的实际容量。库可以实现不同的策略的增长到内存使用和重新分配之间的平衡,但在任何情况下,再分配应仅在对数生长的间隔发生尺寸,使得在所述载体的末端各个元件的插入可以与提供分期常量时间复杂性。 -因此,与阵列相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。 +因此,与数组相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。 与其他动态序列容器(deques,lists和 forward\_lists )相比,vector非常有效地访问其元素(就像数组一样),并相对有效地从元素末尾添加或移除元素。对于涉及插入或移除除了结尾之外的位置的元素的操作,它们执行比其他位置更差的操作,并且具有比列表和 forward\_lists 更不一致的迭代器和引用。 @@ -689,7 +689,7 @@ vector是表示可以改变大小的数组的序列容器。 * 在尾部增删元素 - 平摊(amortized)常数 O(1)}} * 增删元素 - 至 vector 尾部的线性距离 O(n)}} -``` +```cpp template < class T, class Alloc = allocator > class vector; ``` ![](http://img.blog.csdn.net/20160406151211233) @@ -710,7 +710,7 @@ x保持未指定但有效的状态。 (6)初始化列表构造函数 构造一个容器中的每个元件中的一个拷贝的IL,以相同的顺序。 -``` +```cpp default (1) explicit vector (const allocator_type& alloc = allocator_type()); fill (2) @@ -732,7 +732,7 @@ vector (initializer_list il, const allocator_type& alloc = allocator_type()); ``` Example -``` +```cpp #include #include @@ -762,12 +762,12 @@ The contents of fifth are: 16 2 77 29 ``` #### vector::~vector 销毁容器对象。这将在每个包含的元素上调用allocator_traits::destroy,并使用其分配器释放由矢量分配的所有存储容量。 -``` +```cpp ~vector(); ``` #### vector::operator= 将新内容分配给容器,替换其当前内容,并相应地修改其大小。 -``` +```cpp copy (1) vector& operator= (const vector& x); move (2) @@ -812,11 +812,11 @@ Size of bar: 3 这是vector中保存的实际对象的数量,不一定等于其存储容量。 -``` +```cpp size_type size() const noexcept; ``` Example -``` +```cpp #include #include @@ -848,11 +848,11 @@ Output 返回该vector可容纳的元素的最大数量。由于已知的系统或库实现限制, 这是容器可以达到的最大潜在大小,但容器无法保证能够达到该大小:在达到该大小之前的任何时间,仍然无法分配存储。 -``` +```cpp size_type max_size() const noexcept; ``` Example -``` +```cpp #include #include @@ -885,12 +885,12 @@ max_size: 1073741823 如果n也大于当前的容器的capacity(容量),分配的存储空间将自动重新分配。 注意这个函数通过插入或者删除元素的内容来改变容器的实际内容。 -``` +```cpp void resize (size_type n); void resize (size_type n, const value_type& val); ``` Example -``` +```cpp #include #include @@ -919,11 +919,11 @@ myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0 ``` #### vector::capacity 返回当前为vector分配的存储空间的大小,用元素表示。这个capacity(容量)不一定等于vector的size。它可以相等或更大,额外的空间允许适应增长,而不需要重新分配每个插入。 -``` +```cpp size_type capacity() const noexcept; ``` Example -``` +```cpp #include #include @@ -948,11 +948,11 @@ max_size: 1073741823 ``` #### vector::empty 返回vector是否为空(即,它的size是否为0) -``` +```cpp bool empty() const noexcept; ``` Example -``` +```cpp #include #include @@ -986,11 +986,11 @@ total: 55 在所有其他情况下,函数调用不会导致重新分配,并且vector容量不受影响。 这个函数对vector大小没有影响,也不能改变它的元素。 -``` +```cpp void reserve (size_type n); ``` Example -``` +```cpp #include #include @@ -1041,11 +1041,11 @@ capacity changed: 100 要求容器减小其capacity(容量)以适应其尺寸。 该请求是非绑定的,并且容器实现可以自由地进行优化,并且保持capacity大于其size的vector。 这可能导致重新分配,但对矢量大小没有影响,并且不能改变其元素。 -``` +```cpp void shrink_to_fit(); ``` Example -``` +```cpp #include #include @@ -1085,7 +1085,7 @@ Possible output 在初始化列表版本(3)中,新内容是以相同顺序作为初始化列表传递的值的副本。 所述内部分配器被用于(通过其性状),以分配和解除分配存储器如果重新分配发生。它也习惯于摧毁所有现有的元素,并构建新的元素。 -``` +```cpp range (1) template void assign (InputIterator first, InputIterator last); @@ -1095,7 +1095,7 @@ initializer list (3) void assign (initializer_list il); ``` Example -``` +```cpp #include #include @@ -1185,12 +1185,12 @@ vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x) 在vector的最后一个元素之后添加一个新元素。val的内容被复制(或移动)到新的元素。 这有效地将容器size增加了一个,如果新的矢量size超过了当前vector的capacity,则导致所分配的存储空间自动重新分配。 -``` +```cpp void push_back (const value_type& val); void push_back (value_type&& val); ``` Example -``` +```cpp #include #include @@ -1215,11 +1215,11 @@ int main () 删除vector中的最后一个元素,有效地将容器size减少一个。 这破坏了被删除的元素。 -``` +```cpp void pop_back(); ``` Example -``` +```cpp #include #include @@ -1250,7 +1250,7 @@ The elements of myvector add up to 600 通过在指定位置的元素之前插入新元素来扩展该vector,通过插入元素的数量有效地增加容器大小。 这会导致分配的存储空间自动重新分配,只有在新的vector的size超过当前的vector的capacity的情况下。 由于vector使用数组作为其基础存储,因此除了将元素插入到vector末尾之后,或vector的begin之前,其他位置会导致容器重新定位位置之后的所有元素到他们的新位置。与其他种类的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是低效的操作。 -``` +```cpp single element (1) iterator insert (const_iterator position, const value_type& val); fill (2) @@ -1264,7 +1264,7 @@ initializer list (5) iterator insert (const_iterator position, initializer_list il); ``` Example -``` +```cpp #include #include @@ -1326,12 +1326,12 @@ int main() 这有效地减少了被去除的元素的数量,从而破坏了容器的大小。 由于vector使用一个数组作为其底层存储,所以删除除vector结束位置之后,或vector的begin之前的元素外,将导致容器将段被擦除后的所有元素重新定位到新的位置。与其他种类的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是低效的操作。 -``` +```cpp iterator erase (const_iterator position); iterator erase (const_iterator first, const_iterator last); ``` Example -``` +```cpp #include #include @@ -1366,11 +1366,11 @@ myvector contains: 4 5 7 8 9 10 在调用这个成员函数之后,这个容器中的元素是那些在调用之前在x中的元素,而x的元素是在这个元素中的元素。所有迭代器,引用和指针对交换对象保持有效。 请注意,非成员函数存在具有相同名称的交换,并使用与此成员函数相似的优化来重载该算法。 -``` +```cpp void swap (vector& x); ``` Example -``` +```cpp #include #include @@ -1403,11 +1403,11 @@ bar contains: 100 100 100 从vector中删除所有的元素(被销毁),留下size为0的容器。 不保证重新分配,并且由于调用此函数, vector的capacity不保证发生变化。强制重新分配的典型替代方法是使用swap:`vector().swap(x); // clear x reallocating ` -``` +```cpp void clear() noexcept; ``` Example -``` +```cpp #include #include @@ -1467,12 +1467,12 @@ v1 capacity = 5 该元素是通过调用allocator_traits::construct来转换args来创建的。插入一个类似的成员函数,将现有对象复制或移动到容器中。 -``` +```cpp template iterator emplace (const_iterator position, Args&&... args); ``` Example -``` +```cpp #include #include @@ -1504,7 +1504,7 @@ myvector contains: 10 200 100 20 30 300 该元素是通过调用allocator_traits :: construct来转换args来创建的。 与push\_back相比,emplace\_back可以避免额外的复制和移动操作。 -``` +```cpp template void emplace_back (Args&&... args); ``` @@ -1573,11 +1573,11 @@ Franklin Delano Roosevelt was re-elected president of the USA in 1936. ``` #### vector::get_allocator 返回与vector关联的构造器对象的副本。 -``` +```cpp allocator_type get_allocator() const noexcept; ``` Example -``` +```cpp #include #include @@ -1628,7 +1628,7 @@ deque上常见操作的复杂性(效率)如下: * 随机访问 - 常数O(1) * 在结尾或开头插入或移除元素 - 摊销不变O(1) * 插入或移除元素 - 线性O(n) -``` +```cpp template < class T, class Alloc = allocator > class deque; ``` ![](http://img.blog.csdn.net/20170727225856144?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRlg2Nzc1ODg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) @@ -1639,7 +1639,7 @@ template < class T, class Alloc = allocator > class deque; 构造一个deque容器对象,根据所使用的构造函数版本初始化它的内容: Example -``` +```cpp #include #include @@ -1674,12 +1674,12 @@ The contents of fifth are: 16 2 77 29 在当前的最后一个元素之后 ,在deque容器的末尾添加一个新元素。val的内容被复制(或移动)到新的元素。 这有效地增加了一个容器的大小。 -``` +```cpp void push_back (const value_type& val); void push_back (value_type&& val); ``` Example -``` +```cpp #include #include @@ -1704,12 +1704,12 @@ int main () 在deque容器的开始位置插入一个新的元素,位于当前的第一个元素之前。val的内容被复制(或移动)到插入的元素。 这有效地增加了一个容器的大小。 -``` +```cpp void push_front (const value_type& val); void push_front (value_type&& val); ``` Example -``` +```cpp #include #include @@ -1736,11 +1736,11 @@ Output 这破坏了被删除的元素。 -``` +```cpp void pop_back(); ``` Example -``` +```cpp #include #include @@ -1771,11 +1771,11 @@ The elements of mydeque add up to 60 删除deque容器中的第一个元素,有效地减小其大小。 这破坏了被删除的元素。 -``` +```cpp void pop_front(); ``` Example -``` +```cpp #include #include @@ -1812,12 +1812,12 @@ The final size of mydeque is 0 该元素是通过调用allocator_traits::construct来转换args来创建的。 存在一个类似的成员函数push_front,它可以将现有对象复制或移动到容器中。 -``` +```cpp template void emplace_front (Args&&... args); ``` Example -``` +```cpp #include #include @@ -1848,12 +1848,12 @@ mydeque contains: 222 111 10 20 30 该元素是通过调用allocator_traits::construct来转换args来创建的。 存在一个类似的成员函数push_back,它可以将现有对象复制或移动到容器中 -``` +```cpp template void emplace_back (Args&&... args); ``` Example -``` +```cpp #include #include @@ -1894,7 +1894,7 @@ forward\_list(单向链表)被实现为单链表; 单链表可以将它们 #### forward\_list::forward\_list -``` +```cpp default (1) explicit forward_list (const allocator_type& alloc = allocator_type()); fill (2) @@ -1916,7 +1916,7 @@ forward_list (initializer_list il, const allocator_type& alloc = allocator_type()); ``` Example -``` +```cpp #include #include @@ -1959,12 +1959,12 @@ sixth: 3 52 25 90 返回的迭代器不应被解除引用:它是为了用作成员函数的参数emplace\_after,insert\_after,erase\_after或splice\_after,指定序列,其中执行该动作的位置的开始位置。 -``` +```cpp iterator before_begin() noexcept; const_iterator before_begin() const noexcept; ``` Example -``` +```cpp #include #include @@ -1991,11 +1991,11 @@ mylist contains: 11 20 30 40 50 一个常量性是指向常量内容的迭代器。这个迭代器可以增加和减少(除非它本身也是const),就像forward\_list::before\_begin返回的迭代器一样,但不能用来修改它指向的内容。 返回的价值不得解除引用。 -``` +```cpp const_iterator cbefore_begin() const noexcept; ``` Example -``` +```cpp #include #include @@ -2035,11 +2035,13 @@ map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped 在映射中,键值通常用于对元素进行排序和唯一标识,而映射的值存储与此键关联的内容。该类型的键和映射的值可能不同,并且在部件类型被分组在一起VALUE_TYPE,这是一种对类型结合两种: -`typedef pair value_type;` +```cpp +typedef pair value_type; +``` 在内部,映射中的元素总是按照由其内部比较对象(比较类型)指示的特定的严格弱排序标准按键排序。映射容器通常比unordered_map容器慢,以通过它们的键来访问各个元素,但是它们允许基于它们的顺序对子集进行直接迭代。 在该映射值地图可以直接通过使用其相应的键来访问括号运算符((操作符[] )。 映射通常如实施 -``` +```cpp template < class Key, // map::key_type class T, // map::mapped_type class Compare = less, // map::key_compare @@ -2072,7 +2074,7 @@ x保持未指定但有效的状态。 用il中的每个元素的副本构造一个容器。 -``` +```cpp empty (1) explicit map (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()); @@ -2094,7 +2096,7 @@ map (initializer_list il, const allocator_type& alloc = allocator_type()); ``` Example -``` +```cpp #include #include @@ -2132,12 +2134,12 @@ int main () 由于map容器始终保持其元素的顺序,所以开始指向遵循容器排序标准的元素。 如果容器是空的,则返回的迭代器值不应被解除引用。 -``` +```cpp iterator begin() noexcept; const_iterator begin() const noexcept; ``` Example -``` +```cpp #include #include @@ -2166,11 +2168,11 @@ c => 300 #### map::key_comp 返回容器用于比较键的比较对象的副本。 -``` +```cpp key_compare key_comp() const; ``` Example -``` +```cpp #include #include @@ -2208,11 +2210,11 @@ c => 300 #### map::value_comp 返回可用于比较两个元素的比较对象,以获取第一个元素的键是否在第二个元素之前。 -``` +```cpp value_compare value_comp() const; ``` Example -``` +```cpp #include #include @@ -2249,12 +2251,12 @@ z => 3003 如果容器的比较对象自反地返回假(即,不管元素作为参数传递的顺序),则两个key被认为是等同的。 另一个成员函数map::count可以用来检查一个特定的键是否存在。 -``` +```cpp iterator find (const key_type& k); const_iterator find (const key_type& k) const; ``` Example -``` +```cpp #include #include @@ -2294,11 +2296,11 @@ d => 200 由于地图容器中的所有元素都是唯一的,因此该函数只能返回1(如果找到该元素)或返回零(否则)。 如果容器的比较对象自反地返回错误(即,不管按键作为参数传递的顺序),则两个键被认为是等同的。 -``` +```cpp size_type count (const key_type& k) const; ``` Example -``` +```cpp #include #include @@ -2344,12 +2346,12 @@ g is not an element of mymap. 如果map类用默认的比较类型(less)实例化,则函数返回一个迭代器到第一个元素,其键不小于k。 一个类似的成员函数upper\_bound具有相同的行为lower\_bound,除非映射包含一个key值等于k的元素:在这种情况下,lower\_bound返回指向该元素的迭代器,而upper\_bound返回指向下一个元素的迭代器。 -``` +```cpp iterator lower_bound (const key_type& k); const_iterator lower_bound (const key_type& k) const; ``` Example -``` +```cpp #include #include @@ -2393,12 +2395,12 @@ e => 100 类似的成员函数lower\_bound具有与upper\_bound相同的行为,除了map包含一个元素,其键值等于k:在这种情况下,lower\_bound返回指向该元素的迭代器,而upper\_bound返回指向下一个元素的迭代器。 -``` +```cpp iterator upper_bound (const key_type& k); const_iterator upper_bound (const key_type& k) const; ``` Example -``` +```cpp #include #include @@ -2440,12 +2442,12 @@ e => 100 如果没有找到匹配,则返回的范围具有零的长度,与两个迭代器指向具有考虑去后一个密钥对所述第一元件ķ根据容器的内部比较对象(key\_comp)。如果容器的比较对象返回false,则两个键被认为是等价的。 -``` +```cpp pair equal_range (const key_type& k) const; pair equal_range (const key_type& k); ``` Example -``` +```cpp #include #include @@ -2510,12 +2512,12 @@ unordered\_map、unodered\_multimap结构: 元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。 -``` +```cpp template class tuple; ``` Example -``` +```cpp #include // std::cout #include // std::tuple, std::get, std::tie, std::ignore @@ -2578,7 +2580,7 @@ foo contains: 100 y 和上面的版本一样,除了每个元素都是使用allocator alloc构造的。 -``` +```cpp default (1) constexpr tuple(); copy / move (2) @@ -2619,7 +2621,7 @@ template tuple (allocator_arg_t aa, const Alloc& alloc, pair&& pr); ``` Example -``` +```cpp #include // std::cout #include // std::make_pair #include // std::tuple, std::make_tuple, std::get @@ -2656,7 +2658,7 @@ pair的实现是一个结构体,主要的两个成员变量是first second 因 * 可以将两个类型数据组合成一个如map * 当某个函数需要两个返回值时 -``` +```cpp template struct pair; ``` #### pair::pair @@ -2681,7 +2683,7 @@ template struct pair; 构造成员 first 和 second 到位,传递元素first\_args 作为参数的构造函数 first,和元素 second\_args 到的构造函数 second 。 -``` +```cpp default (1) constexpr pair(); copy / move (2) @@ -2700,7 +2702,7 @@ template Example -``` +```cpp #include // std::pair, std::make_pair #include // std::string #include // std::cout @@ -2726,4 +2728,4 @@ Output The price of lightbulbs is $0.99 The price of shoes is $39.9 The price of tomatoes is $2.3 -``` \ No newline at end of file +``` diff --git a/images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png b/images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png new file mode 100644 index 0000000..bb00a04 Binary files /dev/null and b/images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png differ diff --git a/images/TCP的拥塞控制流程图.png b/images/TCP的拥塞控制流程图.png new file mode 100644 index 0000000..c17042c Binary files /dev/null and b/images/TCP的拥塞控制流程图.png differ diff --git a/images/利用可变窗口进行流量控制举例.png b/images/利用可变窗口进行流量控制举例.png new file mode 100644 index 0000000..c62dc8f Binary files /dev/null and b/images/利用可变窗口进行流量控制举例.png differ diff --git a/images/快重传示意图.png b/images/快重传示意图.png new file mode 100644 index 0000000..0acf614 Binary files /dev/null and b/images/快重传示意图.png differ