凡科建设网站还用买服务器吗,跑步机 东莞网站建设,买CAD设计图做的网站,网站前后台代码特性关系 
C语言面向过程C面向过程  面向对象(封装 继承 多态)C具备C语言的全部特性的基础上#xff0c;并且支持更多新的特性
内存泄露 
申请内存#xff0c;没有释放申请 malloc new释放 free deleteProcessExplorer查看内存是否释放
代码移植 
将生成的exe运行在别的平台面向过程  面向对象(封装 继承 多态)C具备C语言的全部特性的基础上并且支持更多新的特性
内存泄露 
申请内存没有释放申请 malloc new释放 free deleteProcessExplorer查看内存是否释放
代码移植 
将生成的exe运行在别的平台不因为缺乏环境而出错使用软件 ProcessExplorer软件查找exe程序执行需要的dll等配置文件或者在程序编译的时候整合对应的库文件(属性-C/C - 代码生成 -运行库)多线程 MT                    静态编译 - 链接库文件多线程调试 MTH          静态编译 - 链接库文件多线程 DLL MD多线程调试DLL MDT
pragma once 
确保.h文件减少包含减少编译错误
C输入输出方式 
输入  输入设备- 输入流-scanf/cin - 变量    cinab;输出  变量 -  printf/cout - 输出流 - 输出设备  cout a  endl;endl输出换行不需要关注 数据类型 和 占位符号
命名空间 
std 关键字 namespace 不同的命名空间使用相同的变量名字和函数使用  命名空间:: 函数名  进行函数的调用数据类型 
布尔类型 bool 真 true假 falsebool flag  false;std::cout  boolalpha  flag  endl;//输出false特性C随用随定义
引用 
一般作为函数的参数这样就不需要返回数据直接取元素的数值 引用避免了申请多个变量大家对引用的使用都是针对同一个元素进行函数默认值 
缺省值 default value函数使用默认值 void fun(int i,int j  7,int k  8)  有默认值的参数必须在参数表的最右端声明和定义同时给出默认值有些编译器会报错。最好在函数的声明时给出默认值
void fun(int i,int j  7,int k  8){std::cout  i    i  std::endl;std::cout  j    j  std::endl;std::cout  k    k  std::endl;
}int main(void)
{int i  7;fun(i);return 0;
} 
函数的重载 
重载函数的参数的个数、参数的类型、参数的顺序三者中必须至少有一种不同返回值不同不作为重载依据重载函数的功能应该相近不可以为了重载而重载main函数不可以重载
内存管理 
栈区由编译器自动分配释放   char型指针p全局区静态区static存放全局变量、静态数据、常量  int x  0;x属于全局变量文字常量区常量字符串就是存放在这里程序结束之后由系统释放    文字常量 Hello程序代码区存放函数体的二进制代码   整个代码的二进制数据堆区程序员申请/释放内存   由程序员申请释放
int x  0;
int main(void)
{char *p  Hello;x  10;return 0;
} 
申请内存 new                 释放内存 deleteint *p  new int;              delete p;int *p  new int(10);       delete p;int *p  new int[5];          delete []p;内存申请有可能失败 if (p  null) return False; p  null;最后让指针指向null内存忘记释放会产生内存的泄露如果需要大的内存 启用大地址输入和输出都是相对于内存来说的内存的特点是 有电则生断电则往文件的输出 常量const 
关键字 修饰一个变量使其成为常量const int x  0; 等价于  int const x  0const int * p  0; 等价于 int const * p  0;int * const p  0;const int * const p  0; 等价于 int const * const p  0;const 修饰普通数据类型 const int x  0; x10;错误const修饰指针类型    int const *p  x; const修饰*因此p可以变化但是*p 不可以int * const p  x;const 修饰p因此*p可以变化 但是p不可以//const 修饰指针类型int x0,y0;int const *p  x;*p  4;//错误p  y;//正确 //const 修饰指针类型int x0,y0;int *const p  x;*p  4;//错误p  y;//正确 
const修饰函数参数int max(const int x,const int y)  代码内部无法对其修改int max(int const *p,int *const q)#define 和const定义常量的区别#define是预编译器只进行字符串替换const在编译的时候进行参数的检查
类和对象之间的关系 
类 抽象对象 具体class类关键字 类名 数据成员  成员函数访问限定符号  public private protected 访问限定符号 可以多次使用
class Student{
public:char name[20];int gender;int age;void study(){std::cout  learning!  std::endl;}private:}; 
属性的封装 
通过set和get的方式对成员变量进行封装通过函数将private私有属性 进行返回
类的实例化 
栈中定义 Car car;     操作系统会回收资源堆中定义  Car *p  new Car();     资源需要由程序员进行释放
类成员的访问 
栈中定义 Car car;   car.getWheelCount();                         .         操作系统释放资源堆中定义 Car *p  new Car();  p-getWheelCount();        -       delete p; p  nullptr;相似于结构体(struct)类的默认访问权限是private  结构体的默认访问权限是publicstruct结构体的使用和函数类似也可以使用上述 堆和栈的方式进行定义Student *p  new Student[20];//定义20个学生变量p[0].age  10;控制第一个学生的age变量  使用delete[] p删除内存空间
#include iostream
#include fstream
#include sstreamstruct Student{
public:char name[20];int age;void study(){std::cout  learning!  std::endl;}private:int gender;int money;
};
int main(void)
{Student student{};student.study();Student *p  new Student[20];p[0].study();delete []p;p  nullptr;return 0;
} 
类内定义和类外定义 
类内定义 建议编译器使用内联方式进行编译如图所示普通函数需要进行函数的跳转而内联函数将需要跳转的函数拷贝到指定的位置避免了函数的拷贝即避免了2和4的步骤只剩下3的步骤并且使用实参进行参数的替代逻辑简单的函数才会使用内联的方式如果函数很复杂就按照普通函数处理内联函数和宏函数 
宏函数走预编译器 内联函数走编译器宏函数没有参数类型的要求不会进行参数检查
类内定义和类外定义 命名规范 
类名单词首字母大写文件名字 和 类名 相同函数名第二个单词首字母大写由单词或动宾短语构成数据成员以(m_类型)作为前缀  int m_i   m作为类内成员变量
对象的存储结构 
类申明多个对象每个对象占据不同的地址类内的函数 只有一份共同调用
构造函数 
实例化对象的时候 自动调用构造函数名字 和 类名相同并且没有返回值如果没有自定义构造函数系统提供默认构造函数构造函数可以使用 带参数的进行初始化构造函数 可以重载系统构造函数 Student(){} 也叫默认构造函数有了自定义的构造函数系统的构造函数还可以使用吗不可以。如果自定义了带参数构造函数使用的时候使用不带参数的默认构造函数会造成错误。因为用户定义了构造函数系统就不会再产生默认构造函数
初始化列表 使用Car():m_iWheelCount(4);进行初始化初始化列表 伴随着构造函数在构造函数的后面使用 : 进行对变量的赋值即使是const修饰的变量  也可以使用初始化列表进行 赋值
#include iostream
#include fstream
#include sstreamclass Car{
public:Car():m_iWheelCount(4),m_iSpeed(0){};void getWheelCount(){std::cout  m_iWheelCount  std::endl;std::cout  m_iSpeed  std::endl;}
private:const int m_iWheelCount;int m_iSpeed;
};
int main(void)
{Car car;car.getWheelCount();return 0;
} 
拷贝构造函数 
对象初始化的两种方式 直接初始化  int x  1024;复制初始化  Student stu(stu1);如上图所示 stu1 使用默认构造函数stu2 和 stu3 使用  拷贝构造函数拷贝构造函数的特点1如果没有自定义的拷贝构造函数 则系统自动生成2当对象直接初始化 或者  复制初始化  时候 自动调用拷贝构造函数3当自定义了拷贝构造函数则系统 不再生成 默认的拷贝构造函数
#include iostream
#include fstream
#include sstreamclass Car{
public:Car(){};Car(const Car car){ //拷贝构造初始化std::cout  Car(const Car car)  std::endl;}
private:};
int main(void)
{Car car1;         //直接初始化Car car2(car1);   //拷贝构造初始化Car car3  car1;  //拷贝构造初始化return 0;
} 
类的析构函数 
析构函数名字 如 ~类名(){}析构函数没有参数析构函数没有返回数值析构函数不可以重载析构函数 销毁时候 自动执行堆 和 栈 使用一致
#include iostream
#include fstream
#include sstreamclass Car{
public:Car(){std::cout   对象创建  std::endl;};~Car(){std::cout   对象销毁   std::endl;}
private:};
int main(void)
{Car *car  new Car();delete car;car  nullptr;return 0;
} 
什么时候需要自定义析构函数比如在堆上申请了一大段内存空间使用delete []p进行资源的释放
#include iostream
#include fstream
#include sstreamclass Car{
public:Car(){m_pName  new char [20];std::cout   对象创建  std::endl;};~Car(){delete[] m_pName;std::cout   对象销毁   std::endl;}
private:char *m_pName;
};
int main(void)
{Car *car  new Car();delete car;car  nullptr;return 0;
} 
当函数参数是一个对象的时候使用拷贝构造函数
对象成员 
多个类之间互相使用调用使用得到对象
对象数组 
#include iostreamclass Coordinate{
public:int m_iX;int m_iY;
};
int main(void)
{Coordinate coord[3]; //栈上申请内存coord[1].m_iX  4;Coordinate *p  new Coordinate[3]; //堆上申请内存p[0].m_iX  20;delete []p;//删除对象数组p  nullptr;return 0;
} 
应该使用delete []p方式删除对象数组不加上[] 只会清除一个对象
静态数据成员 
静态数据成员 放在全局区静态数据成员 没有对象仍然可以使用静态数据成员 与 类  同生共死静态成员函数 只可以使用 静态数据成员  非静态成员函数 可以使用 静态数据成员
#include iostreamclass Tank{
public:Tank(std::string code);~Tank();void attack();static int getCount();
private:std::string m_strCode;static int g_iCount;
};
int Tank::g_iCount  0;Tank::Tank(std::string code) {m_strCode  code;g_iCount;
}Tank::~Tank() {g_iCount--;
}
void Tank::attack() {if (g_iCount  3){std::cout    std::endl;} else{std::cout    std::endl;}
}int Tank::getCount() {return g_iCount;
}int main(void)
{std::cout  Tank::getCount  std::endl;return 0;
} 
对象指针成员 
对象成员    如图左边所示对象A的构造函数需要先等对象B构造完成之后才执行对象A的构造函数对象成员指针  如图右边所示对象B的指针不会提前执行对象B的构造函数直接进行对象A的构造函数对象B的构造函数 伴随其过程而产生this指针 
this进行同名变量之间使用this标记当前对象this指向这个类每个对象都有自己的this指针每个this指针都指向该对象的首地址#include iostreamclass Student{
public:Student(std::string name);Student* getIt1();        //获取当前对象的指针Student getIt2();        //获取当前对象void getIt3(Student **it); //获取当前对象指针void getIt4(Student it); //通过传入引用 获取当前对象void printName();//打印名字void setName(std::string name);//设置名字
private:std::string m_strName;
};Student::Student(std::string name) {this-m_strName  name;
}Student * Student::getIt1() {return this;
}Student Student::getIt2() {return *this;//返回this指针指向的对象
}void Student::getIt3(Student **it) {*it  this;
}void Student::getIt4(Student it) {it  *this;
}void Student::printName() {std::cout  m_strName  std::endl;
}void Student::setName(std::string name) {m_strName  name;
}
int main() {//测试 getIt1
//    Student stu(zhangsan);
//    Student *p  stu.getIt1();
//    p-printName();
//    Student stu1(lisi);
//    p  stu1.getIt1();
//    p-printName();//测试 getIt2
//    Student stu(zhangsan);
//    stu.printName();
//    Student stu1  stu.getIt2();
//    stu1.setName(lisi);
//    stu1.printName();//测试 getIt3   *无法拿到指针指向的数据  需要使用**
//    Student stu(zhangsan);
//    Student *p  nullptr;
//    stu.printName();
//    stu.getIt3(p); //注意
//    p-printName();//测试 getIt4Student stu(zhangsan);Student stu1(liis);stu.getIt4(stu1);stu1.printName();return 0;
}常成员函数 
在函数的名字后面添加 const表示这个函数是常成员函数在常成员函数中不能改变数据成员的数值const 也是函数重载的一个特性只有常对象 才可以使用  常成员函数常对象指针常对象引用
#include iostreamclass Student{
public:Student(std::string name);void printInfo();//常成员函数//重载函数void printInfo() const;
private:std::string m_strName;
};void Student::printInfo() {std::cout  m_strName  std::endl;
}void Student::printInfo() const {//在常成员函数中不能改变数据成员的数值std::cout  m_strName  std::endl;
}int main() {Student s1(zhangsan);s1.printInfo();const Student s2(lisi);//1常对象//修饰的时候 const 可以放在Student的前面 或者 后面s2.printInfo();Student *s3  new Student(Merry);s3-printInfo();//2常对象指针Student const *s4  new Student(Jim);s4-printInfo();Student s5(Merry);Student s6  s5;Student const s7  s5;//常对象引用s6.printInfo();s7.printInfo();return 0;
}深拷贝和浅拷贝 
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体而不是引用。假设B复制了A修改A的时候看B是否发生变化如果B跟着也变了说明是浅拷贝修改堆内存中的同一个值如果B没有改变说明是深拷贝修改堆内存中的不同的值深拷贝和浅拷贝的区别
友元函数 
friend  友元全局函数friend 类型 函数名字 (形参列表)友元成员函数  friend 类型 类名::函数名字(形参表)友元  不可以传递友元  是单向的私有private变量  通过申明为友元函数访问 私有变量friend友元函数 放在private public 都可以不影响使用但是一般放在类的最前边
友元全局函数 Time.h 
#pragma onceclass Time{friend void printTime(Time t);// 友元全局函数(当前类  引用)
//    friend void Student::setTime(Time t);//友元成员函数(类名  函数名字)
public:Time(int year,int month,int day){m_iYear  year;m_iMonth  month;m_iDay  day;};
private:int m_iYear;int m_iMonth;int m_iDay;
};主函数 
#include iostream
#include lib/Time.hvoid printTime(Time t);int main() {Time t1(2015,8,7);printTime(t1);return 0;
}void printTime(Time t){std::cout  t.m_iYear -  t.m_iMonth  -  t.m_iDay  std::endl;
}友元成员函数   
#includeiostream
using namespace std;class Date;//对Date类的提前引用声明
class Time
{
public:Time(int, int, int);//声明构造函数void display(Date );
private:int hour;int sec;int minute;
};class Date
{
public:Date(int, int, int);//声明构造函数friend void Time::display(Date );
private:int mouth;int day;int year;
};Time::Time(int h, int m, int s)
{hour  h;minute  m;sec  s;
}void Time::display(Date d)//display的作用是输出年月日时分秒
{cout  d.mouth  /  d.day  /  d.year  endl;cout  hour  :  minute  :  sec  endl;
}Date::Date(int m, int d, int y)
{mouth  m;day  d;year  y;
}int main(void)
{Time t1(10, 13, 56);Date d1(4, 15, 2019);t1.display(d1);return 0;
}友元 一般是在先前代码上进行使用准确说是一种设计缺陷的弥补措施尽量不要使用
继承 
父类 叫做 基类子类 叫做 派生类父类是抽象子类是在父类抽象的基础上进一步的细化比如父类是人子类是工人子类的子类是 电工逐步细化
三种派生方式 
公有派生  公有继承  public保护派生  保护继承  protected私有派生  私有继承  private多继承 
一个类继承了多个类。比如童工类  继承  儿童类 的同时  也继承了 工人类
多重继承 
类和类之间逐级继承。比如 技术工人类  继承  工人类电焊工人类  继承  技术工人类
菱形继承 
类和类之间的继承关系构成了一个菱形比如 工人类 和 农民类都继承自  人类而农民工类  继承了工人类 和  农民类。四者之间构成了一个菱形为了解决这个问题需要使用虚继承 或者在  头文件引用 #pragma once
公有继承 
如果未定义 默认使用  私有派生  私有继承  private子类 派生自 父类。所以先执行 父类的构造函数 再 执行 子类的构造函数销毁的时候先执行 子类的析构函数 再执行 父类的析构函数通过在父类 添加字段和方法影响子类。而且派生自不同的父类子类之间的影响是最低的父类 的 private成员子类无法访问
#include iostreamclass Worker{
public:Worker(std::string name,std::string code);~Worker();std::string getName() const;
protected:std::string m_strName;std::string m_strCode;
};Worker::Worker(std::string name,std::string code) {m_strName  name;m_strCode  code;
}Worker::~Worker() {}std::string Worker::getName() const {return m_strName;
}class Electrician : public Worker{
public:Electrician(std::string name,std::string code,size_t salary):Worker(name,code){m_iSalary  salary;};void printInfo() const{std::cout  m_strName    m_strCode     m_iSalary  std::endl;}protected:size_t m_iSalary;
};int main(void)
{Electrician *electrician  new Electrician(Jim,1234,1200000);std::cout  electrician-getName()  std::endl;electrician-printInfo();return 0;
} 
三种继承方式 
public        公有继承方式   父类的public 派生到 子类的public父类的protected 派生到 子类的protected父类的private 对于子类不可见protected  保护继承方式   父类的public 派生到 子类的protected父类的protected 派生到 子类的protected父类的private 对于子类不可见private      私有继承方式   父类的public 派生到 子类的private父类的protected 派生到 子类的privat父类的private 对于子类不可见
同名隐藏 
父类 和 子类 的成员函数的名字一致参数无限制成员函数的名字一样但是所处的作用域不一样比如处于protected public等同名的时候   子类的函数名字  会  隐藏父类的名字但是父类的名字也是可以使用的。比如 使用子类定义的对象.父类的名字::同名的函数的名字();
#include iostreamclass Worker{
public:Worker(std::string name,std::string code);~Worker();std::string getName() const;void printInfo(){std::cout   父类   std::endl;};
protected:std::string m_strName;std::string m_strCode;
};Worker::Worker(std::string name,std::string code) {m_strName  name;m_strCode  code;
}Worker::~Worker() {}std::string Worker::getName() const {return m_strName;
}class Electrician : public Worker{
public:Electrician(std::string name,std::string code,size_t salary):Worker(name,code){m_iSalary  salary;};void printInfo() const{std::cout  m_strName    m_strCode     m_iSalary  std::endl;std::cout   子类   std::endl;}protected:size_t m_iSalary;
};int main(void)
{Electrician *electrician  new Electrician(Jim,1234,1200000);std::cout  electrician-getName()  std::endl;electrician-printInfo();//子类electrician-Worker::printInfo();//父类return 0;
} 
多重继承 
电工类 继承自 技术工人类技术工人类 继承自 工人类逐级继承超过量层就是 多重继承例子m_strName来自Worker、m_strSkill 来自SkillWorker  m_iSalary来自子类独有变量
#include iostreamclass Person{
public:Person(int age);~Person();int getAge();protected:int m_iAge;
};Person::Person(int age) {std::cout  Person  std::endl;m_iAge  age;
}Person::~Person() {std::cout  ~Person  std::endl;
}int Person::getAge() {return m_iAge;
}
class Worker : public Person{
public:Worker(std::string name,int age);~Worker();std::string getName()const;
protected:std::string m_strName;
};
Worker::Worker(std::string name, int age):Person(age) {m_strName  name;std::cout  Worker  std::endl;
}Worker::~Worker() {std::cout  ~Worker  std::endl;
}
std::string Worker::getName() const {return m_strName;
}class Electrician : public Worker{
public:Electrician(std::string name, int age, int salary): Worker(name,age){m_iSalary  salary;std::cout  Electrician  std::endl;};~Electrician(){std::cout  ~Electrician  std::endl;};void printInfo() const;protected:int m_iSalary;
};
int main(void)
{Electrician *electrician  new Electrician(jim,30,233333);delete electrician;electrician  nullptr;return 0;
}//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88 . 88                              //
//                         (| ^_^ |)                              //
//                         O\    /O                              //
//                      ____/---\____                           //
//                    .  \\|     |//  .                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  \---/  |   |                       //
//                  \  .-\__  -  ___/-. /                       //
//                ___. .  /--.--\  . . ___                     //
//              .   .___\_|_/___.  .                  //
//            | | :  - \.;\ _ /;./ -  : | |                 //
//            \  \ -.   \_ __\ /__ _/   .- /  /                 //
//      -.____-.___\_____/___.-____.-         //
//                           ---                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//                  佛祖保佑       永不宕机     永无BUG               //多继承 
多继承是横向的作为一个子类不仅仅拥有一个父类例  在职研究生继承自研究生和职员两个类                 两个类都是实体例  水路两栖坦克继承自坦克和  能水中行驶  两个类  其中一个类表示能力、属性(多态)继承的多个类 需要声明属性并且使用 逗号相隔
#include iostreamclass Farmer{
public:Farmer(int age);~Farmer();int getAge();protected:int m_iAge;
};Farmer::Farmer(int age) {std::cout  Farmer  std::endl;m_iAge  age;
}Farmer::~Farmer() {std::cout  ~Farmer  std::endl;
}int Farmer::getAge() {return m_iAge;
}
class Worker {
public:Worker(std::string name);~Worker();std::string getName()const;
protected:std::string m_strName;
};
Worker::Worker(std::string name) {m_strName  name;std::cout  Worker  std::endl;
}Worker::~Worker() {std::cout  ~Worker  std::endl;
}
std::string Worker::getName() const {return m_strName;
}class MigrantWorker : public Worker,public Farmer{
public:MigrantWorker(std::string name, int age, int salary):Worker(name),Farmer(age){m_iSalary  salary;std::cout  MigrantWorker  std::endl;};~MigrantWorker(){std::cout  ~MigrantWorker  std::endl;};void printInfo() const;protected:int m_iSalary;
};
void MigrantWorker::printInfo() const {std::cout  m_strName     m_iAge     m_iSalary  std::endl;
}
int main(void)
{MigrantWorker *p  new MigrantWorker(001,20,222222);p-printInfo();delete p;p  nullptr;return 0;
} 
菱形继承 
类和类之间的继承关系构成了一个菱形比如 工人类 和 农民类都继承自  人类而农民工类  继承了工人类 和  农民类。四者之间构成了一个菱形为了解决这个问题需要使用虚继承 或者在  头文件引用 #pragma oncePerson               人类Worker               工人Farmer               农民MigrantWorker   农民工工人类 和 农民类  在自己的头文件中引用Person类会多次引用 造成重定义 因此使用  #pragma once  或者#ifndef XXXX 换行 define XXXX 在代码的最末尾输入 #endif农民工 继承的工人和农民都包含了 来自人类的冗余字段即 人类类中的字段 拥有三份分别来自  人类  工人  和农民。因此需要指定 继承的字段来自于哪个特定的类  使用虚继承class MigrantWorker : virtual public Worker   使用virtual将相同的数据成员合并virtual 写在public前后 都可以
注意事项 
结构体 也可以使用 继承机制对于父类是基于属性的不是抽象的实体需要对其进行重写面向对象的三大特征 封装 - 继承 - 多态
多态 虚函数理论 
虚函数  virtual如果不使用虚函数 virtual子类都会使用父类的方法不会使用自己重新定义的方法
#include iostream
#include cmathclass Shape{
public:Shape(){std::cout  Shape  std::endl;};double calcArea(){std::cout  Shape calcArea  std::endl;};
};class Rectangle : public Shape{
public:Rectangle(double width,double height){m_dHeight  height;m_dWidth  width;std::cout  Rectangle  std::endl;}double caleArea(){std::cout  Rectangle calcArea  std::endl;return m_dWidth * m_dHeight;};protected:double m_dWidth;double m_dHeight;
};class Circle : public Shape{
public:Circle(double r){std::cout  Circle  std::endl;m_iR  r;};double caleArea(){std::cout  Circle calcArea  std::endl;return 3.14 * pow(m_iR,2);}protected:double m_iR;
};int main(void)
{Shape *p1  new Rectangle(2.0,3.0);Shape *p2  new Circle(2.0);p1-calcArea();p2-calcArea();return 0;
} Shape.h 
基类中 使用virtual调用的时候将执行子类的方法不再使用父类的方法
#pragma onceclass Shape{
public:Shape();virtual double calcArea();
};Shape::Shape() {std::cout  Shape  std::endl;
}
double Shape::calcArea() {std::cout  Shape calcArea  std::endl;return -1;
} 
Rectangle.h 
#pragma once
#include Shape.hclass Rectangle : public Shape{
public:Rectangle(double width,double height);virtual double calcArea();protected:double m_dWidth;double m_dHeight;
};Rectangle::Rectangle(double width, double height) {m_dHeight  height;m_dWidth  width;std::cout  Rectangle  std::endl;
}double Rectangle::calcArea() {std::cout  Rectangle calcArea  std::endl;return m_dWidth * m_dHeight;
} 
Circle.h 
#pragma once
#include Shape.h
#include cmathclass Circle : public Shape{
public:Circle(double r);double calcArea();protected:double m_iR;
};Circle::Circle(double r) {std::cout  Circle  std::endl;m_iR  r;
}double Circle::calcArea(){std::cout  Circle calcArea  std::endl;return 3.14 * pow(m_iR,2);
} 
main.c 
#include iostream
#include include/Shape.h
#include include/Rectangle.h
#include include/Circle.hint main(void)
{Shape *p1  new Rectangle(2.0,3.0);Shape *p2  new Circle(2.0);p1-calcArea();p2-calcArea();return 0;
} 
虚析构函数 
父类指针 指向子类对象的副作用虚析构函数Shape *p1  new Rectangle(2.0,3.0);  Shape *p2  new Circle(2.0);   delete p1或者p2删除他们指向的内存空间但是 如果Rectangle或者CIrcle内部在堆上 申请的内存 无法通过父类指针 p1 p2 释放内部的内存空间造成内存的泄露需要定义 虚析构函数子类定义自己的析构函数否则自己申请的内存释放定义析构函数之后  delete p1;就会执行子类的析构函数
#include iostream
#include cmathclass Shape{
public:Shape();virtual ~Shape();virtual double calcArea();
};Shape::Shape() {std::cout  Shape  std::endl;
}Shape::~Shape() {std::cout  ~Shape  std::endl;
}double Shape::calcArea() {std::cout  Shape calcArea  std::endl;return -1;
}class Rectangle : public Shape{
public:Rectangle(double width,double height);virtual double calcArea();~Rectangle();
protected:double m_dWidth;double m_dHeight;int *m_pArr;
};Rectangle::Rectangle(double width, double height) {m_dHeight  height;m_dWidth  width;std::cout  Rectangle  std::endl;m_pArr  new int[20];
}double Rectangle::calcArea() {std::cout  Rectangle calcArea  std::endl;return m_dWidth * m_dHeight;
}Rectangle::~Rectangle() {delete []m_pArr;std::cout  ~Rectangle  std::endl;
}class Circle : public Shape{
public:Circle(double r);double calcArea();~Circle();
protected:double m_iR;
};Circle::~Circle() {std::cout  ~Circle  std::endl;
}
Circle::Circle(double r) {std::cout  Circle  std::endl;m_iR  r;
}double Circle::calcArea(){std::cout  Circle calcArea  std::endl;return 3.14 * pow(m_iR,2);
}int main(void)
{Shape *p1  new Rectangle(2.0,3.0);Shape *p2  new Circle(2.0);p1-calcArea();p2-calcArea();delete p1;delete p2;p1  nullptr;p2  nullptr;return 0;
} 
虚函数的实现原理 
虚函数表只放  虚函数指针虚析构函数  先调用子类的析构函数如果父类的析构函数存在再调用父类的析构函数。两者之间使用链表结构衔接任何类型的指针 都占据 4个字节 用于验证虚函数 表指针的存在 (配合sizeof使用)纯虚函数 
基类 virtual double calcArea()  0; 纯虚函数没有函数体当子类继承 基类的纯虚函数 需要对纯虚函数的内容进行 填写含有纯虚函数的类叫做 抽象类Shape *p  new Shape();  //抽象类不可以实例化抽象类不可以new出对象因为对象无法表达内部的函数行为纯虚函数本质基于纯虚函数的子类也可以是子类性质一致直到可以形成对象抽象类中只有纯虚函数呢接口类
纯虚函数 抽象类 
纯虚函数的改正  virtual double calcArea()  0;删除先前的基类对其 的定义
#include iostream
#include cmathclass Shape{
public:Shape();virtual ~Shape();virtual double calcArea()  0;
};Shape::Shape() {std::cout  Shape  std::endl;
}Shape::~Shape() {std::cout  ~Shape  std::endl;
}class Rectangle : public Shape{
public:Rectangle(double width,double height);virtual double calcArea();~Rectangle();
protected:double m_dWidth;double m_dHeight;int *m_pArr;
};Rectangle::Rectangle(double width, double height) {m_dHeight  height;m_dWidth  width;std::cout  Rectangle  std::endl;m_pArr  new int[20];
}double Rectangle::calcArea() {std::cout  Rectangle calcArea  std::endl;return m_dWidth * m_dHeight;
}Rectangle::~Rectangle() {delete []m_pArr;std::cout  ~Rectangle  std::endl;
}class Circle : public Shape{
public:Circle(double r);double calcArea();~Circle();
protected:double m_iR;
};Circle::~Circle() {std::cout  ~Circle  std::endl;
}
Circle::Circle(double r) {std::cout  Circle  std::endl;m_iR  r;
}double Circle::calcArea(){std::cout  Circle calcArea  std::endl;return 3.14 * pow(m_iR,2);
}int main(void)
{Shape *p1  new Rectangle(2.0,3.0);Shape *p2  new Circle(2.0);p1-calcArea();p2-calcArea();delete p1;delete p2;p1  nullptr;p2  nullptr;return 0;
} 
仅仅含有纯虚函数的类 叫做接口类在接口类的基础上 实现部分纯虚函数叫做抽象类  但是没有实现全部  不可以定义对象只有全部实现父类 之路上所有的虚函数才可以定义对象抽象类 和 接口类的用途  抽象类用于表达不完全的实体概念接口类用于表达一种强制协议或者能力
C 数据类型装换 
reinterpret_castnew_type(expression)    将指针和引用的数据类型进行转换dynamic_casttype(expression)                父类和子类数据之间的转换   只有多态才可以采用static_casttype(expression)                     普通数据类型的转换const_casttype(expression)                     const 和 非const之间的转换
#include iostreamclass Shape{
public:Shape();virtual ~Shape();virtual double calcArea();protected:double i_mNumber;
};class Circle : public Shape{
public:Circle(double r);~Circle();
protected:double m_iR;
};
int main(){double x  2.5;//static_castint y  (int)x;//C语言int z  static_castint(x);//C//dynamic_castShape *p  new Circle(2.0);Circle *q  dynamic_castCircle *(p);//reinterpret_castint r  1000;int *w  reinterpret_castint *(r);//将数值转化为地址 很危险//const int c  0;
//    int *o  x;//Errorint *g  const_castint *(c);
}RTTI  
C中的RTTI机制RTTI的主要表现形式是 type_idRTTI的前提是 父类具有虚函数
异常处理 
异常 程序运行期间出现的问题或者错误异常处理处理异常的方法在有可能发生异常的地方做出预见性的安排。异常处理提供了处理程序运行时出现的任何意外或者异常情况的方法C 处理异常基本思想异常 的检测和处理进行分离遇到异常 1遇到错误立即终止程序2返回一个表示错误的数值同时保留错误的信息3针对错误情况再次分析处理throwtry catchcatch(...) 捕捉所有的异常
#include iostreamvoid fun1(){std::cout  fun1  std::endl;throw wer;
}void fun2(){try {fun1();} catch (int e1){std::cout  exception int: e1  std::endl;} catch (double e2) {std::cout  exception double: e2  std::endl;} catch (...) {std::cout  全部捕捉! std::endl;}std::cout  fun2  std::endl;
}
int main(){fun2();
}异常的组织形式  平行机构通过枚举来组织异常1优点语义相关的错误放在一起条理清晰适合一些简单的带有初始值的错误信息2缺点无法详细的描述异常的类型树形结构通过异常的层次关系来组织异常1优点可以在类的内部详细的描述错误的类型2缺点容易造成类层次的无限扩充反而不容易理解
#include iostream#define ERR_OK        0x0000
#define ERR_OK_MSG    OK#define ERR_CARD      0x8101
#define ERR_CARD_MSG  No Card#define ERR_UNKnown   0x8000
#define ERR_UNK_MSG   unknown errorenum MathException{ZeroException  10,NegativeException  20,NoSolutionException  30
};class MyException{
public:MyException(int code,std::string msg);virtual int getErrorInfo(std::string msg);protected:int m_iCode;std::string m_strMsg;
};
MyException::MyException(int code, std::string msg) {std::cout  MyException  std::endl;m_iCode  code;m_strMsg  msg;
}int MyException::getErrorInfo(std::string msg) {std::cout  getErrorInfo  std::endl;msg  m_strMsg;return m_iCode;
}
class HardwareMyException : public MyException{
public:HardwareMyException(int code,std::string msg);virtual int getErrorInfo(std::string msg);
};
HardwareMyException::HardwareMyException(int code, std::string msg) :MyException(code,msg) {std::cout  HardwareMyException  std::endl;
}
int HardwareMyException::getErrorInfo(std::string msg) {std::cout  HardwareMyException  getErrorInfo  std::endl;msg  m_strMsg;return m_iCode;
}void fun1(int flag){switch (flag) {case 0:throw MyException(ERR_CARD,ERR_CARD_MSG);break;case 1:throw MyException(ERR_UNKnown,ERR_UNK_MSG);break;case 2:throw HardwareMyException(ERR_OK,ERR_OK_MSG);break;}
}
int main(){try {fun1(1);} catch (MyException e) {std::string msg;std::cout  e.getErrorInfo(msg)  std::endl;std::cout  msg  std::endl;}
}运算符号重载 
运算符重载的方式1成员函数重载  2友元函数重载一元运算符重载 负号(-)  递增运算符号()  递减运算符号(--)二元运算符重载  加减号(-) 索引符号[]  输出流 不可以重载运算符号 .  .*  ::  ?:   {}   sizeof
成员函数重载 
#includeiostream
using namespace std;class Binomial{
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator-();
private:int m_iA;int m_iB;
};
int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}
Binomial Binomial::operator-() {this-m_iA  -(this-m_iA);m_iB  -m_iB;return *this;//返回对象
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(0,0);bin2  -bin1;std::cout  bin1.getA()  std::endl;std::cout  bin1.getB()  std::endl;std::cout  bin2.getA()  std::endl;std::cout  bin2.getB()  std::endl;return 0;
}友元函数重载  this指针失效 
#includeiostream
using namespace std;class Binomial{friend Binomial operator-(Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();
private:int m_iA;int m_iB;
};int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}
//Binomial Binomial::operator-() {
//    this-m_iA  -(this-m_iA);
//    m_iB  -m_iB;
//    return *this;//返回对象
//}
Binomial operator-(Binomial bin){bin.m_iA  -bin.m_iA;bin.m_iB  -bin.m_iB;return bin;
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(0,0);bin2  -bin1;std::cout  bin1.getA()  std::endl;std::cout  bin1.getB()  std::endl;std::cout  bin2.getA()  std::endl;std::cout  bin2.getB()  std::endl;return 0;
}递增运算符重载 
JJ
#includeiostream
using namespace std;class Binomial{friend Binomial operator-(Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 j
private:int m_iA;int m_iB;
};int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}
//Binomial Binomial::operator-() {
//    this-m_iA  -(this-m_iA);
//    m_iB  -m_iB;
//    return *this;//返回对象
//}
Binomial operator-(Binomial bin){bin.m_iA  -bin.m_iA;bin.m_iB  -bin.m_iB;return bin;
}
Binomial Binomial::operator() {m_iA;m_iB;return *this;
}
Binomial Binomial::operator(int) {Binomial old(*this);m_iA;m_iB;return old;
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(0,0);
//    bin2  -bin1;bin1;std::cout  bin1.getA()  std::endl;std::cout  bin1.getB()  std::endl;//    std::cout  bin2.getA()  std::endl;
//    std::cout  bin2.getB()  std::endl;return 0;
}二元运算符重载  成员函数重载  
#includeiostream
using namespace std;class Binomial{friend Binomial operator-(Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 jBinomial operator(Binomial bin);
private:int m_iA;int m_iB;
};int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}
//Binomial Binomial::operator-() {
//    this-m_iA  -(this-m_iA);
//    m_iB  -m_iB;
//    return *this;//返回对象
//}
Binomial operator-(Binomial bin){bin.m_iA  -bin.m_iA;bin.m_iB  -bin.m_iB;return bin;
}
Binomial Binomial::operator() {m_iA;m_iB;return *this;
}
Binomial Binomial::operator(int) {Binomial old(*this);m_iA;m_iB;return old;
}Binomial Binomial::operator(Binomial bin) {Binomial temp(0,0);temp.m_iA  m_iA  bin.m_iA;temp.m_iB  m_iB  bin.m_iB;return temp;
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(8,-5);Binomial bin3(0,0);bin3  bin1  bin2;std::cout  bin1.getA()  std::endl;std::cout  bin1.getB()  std::endl;std::cout  bin2.getA()  std::endl;std::cout  bin2.getB()  std::endl;std::cout  bin3.getA()  std::endl;std::cout  bin3.getB()  std::endl;return 0;
}
//5
//3
//8
//-5
//13
//-2友元类型 
#includeiostream
using namespace std;class Binomial{friend Binomial operator-(Binomial bin);friend Binomial operator(Binomial bin1,Binomial bin2);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 j
//    Binomial operator(Binomial bin);
private:int m_iA;int m_iB;
};int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}
//Binomial Binomial::operator-() {
//    this-m_iA  -(this-m_iA);
//    m_iB  -m_iB;
//    return *this;//返回对象
//}
Binomial operator-(Binomial bin){bin.m_iA  -bin.m_iA;bin.m_iB  -bin.m_iB;return bin;
}
Binomial Binomial::operator() {m_iA;m_iB;return *this;
}
Binomial Binomial::operator(int) {Binomial old(*this);m_iA;m_iB;return old;
}Binomial operator(Binomial bin1,Binomial bin2){Binomial temp(0,0);temp.m_iA  bin1.m_iA bin2.m_iA;temp.m_iB  bin1.m_iB  bin2.m_iB;return temp;
}
//Binomial Binomial::operator(Binomial bin) {
//    Binomial temp(0,0);
//    temp.m_iA  m_iA  bin.m_iA;
//    temp.m_iB  m_iB  bin.m_iB;
//    return temp;
//}int main(void)
{Binomial bin1(5,3);Binomial bin2(8,-5);Binomial bin3(0,0);bin3  bin1  bin2;std::cout  bin1.getA()  std::endl;std::cout  bin1.getB()  std::endl;std::cout  bin2.getA()  std::endl;std::cout  bin2.getB()  std::endl;std::cout  bin3.getA()  std::endl;std::cout  bin3.getB()  std::endl;return 0;
}
//5
//3
//8
//-5
//13
//-2重载   
只可以使用友元函数重载  不可以使用成员函数因为第一个必须是cout类型
#includeostream
#include iostreamclass Binomial{friend Binomial operator-(Binomial bin);friend Binomial operator(Binomial bin1,Binomial bin2);friend std::ostream operator  (std::ostream out,Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 j
//    Binomial operator(Binomial bin);
private:int m_iA;int m_iB;
};int Binomial::getA() {return m_iA;
}
int Binomial::getB() {return m_iB;
}
Binomial::Binomial(int a, int b) {m_iA  a;m_iB  b;
}
Binomial::~Binomial() {}Binomial operator-(Binomial bin){bin.m_iA  -bin.m_iA;bin.m_iB  -bin.m_iB;return bin;
}
Binomial Binomial::operator() {m_iA;m_iB;return *this;
}
Binomial Binomial::operator(int) {Binomial old(*this);m_iA;m_iB;return old;
}Binomial operator(Binomial bin1,Binomial bin2){Binomial temp(0,0);temp.m_iA  bin1.m_iA bin2.m_iA;temp.m_iB  bin1.m_iB  bin2.m_iB;return temp;
}std::ostream operator  (std::ostream out,Binomial bin){out  bin.m_iA  x  (  bin .m_iB  );return out;
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(8,-5);Binomial bin3(0,0);bin3  bin1  bin2;std::cout  bin1  std::endl;//operator(cout , bin)std::cout  bin2  std::endl;//operator(cout , bin2)std::cout  bin3  std::endl;//operator(cout , bin3)return 0;
} 
索引运算符重载 
一元函数运算 5x  35为a 3为b预期通过 bin[0] 得到a通过bin[1] 得到b
#includeostream
#include iostreamclass Binomial{friend Binomial operator-(Binomial bin);friend Binomial operator(Binomial bin1,Binomial bin2);friend std::ostream operator  (std::ostream out,Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 jint operator[](unsigned int i);
//    Binomial operator(Binomial bin);
private:int m_iA;int m_iB;
};int Binomial::operator[](unsigned int i) {if (i  0){return m_iA;} else if (i  1){return m_iB;} else{throw 1;}
}
int main(void)
{Binomial bin1(5,3);std::cout  bin1[0]  std::endl; //bin.operator[](0)std::cout  bin1[1]  std::endl; //bin.operator[](1)return 0;
} 
等于重载 
#includeostream
#include iostreamclass Binomial{friend Binomial operator-(Binomial bin);friend Binomial operator(Binomial bin1,Binomial bin2);friend std::ostream operator  (std::ostream out,Binomial bin);
public:Binomial(int a,int b);~Binomial();int getA();int getB();Binomial operator();//前置 jBinomial operator(int);//后置 jint operator[](unsigned int i);bool operator(Binomial bin);
//    Binomial operator(Binomial bin);
private:int m_iA;int m_iB;
};bool Binomial::operator(Binomial bin) {if (this-m_iA  bin.m_iA  this-m_iB  bin.m_iB){return true;}else{return false;}
}
int main(void)
{Binomial bin1(5,3);Binomial bin2(4,5);if (bin1  bin2){std::cout  A  std::endl;}else{std::cout  B  std::endl;}return 0;
}运算符重载 
注意事项 
若一个运算的操作需要修改对象的状态选择重载为成员函数也可以使用友元函数修改对象的状态当运算符号所需要的操作数(尤其是第一个操作数)希望有隐式类型转换则只能使用友元函数当需要重载运算符号具有可交换性选择重载为友元函数