一、理论
1、虚函数
1.1、定义:
虚函数就是在类中被关键字virtual声明的函数,一般只在基类中声明虚函数。
1.2、规则:
1、虚函数必须是类的成员函数,不能是类的静态成员函数或友元函数,因为虚函数的调用要靠特定的对象来决定该激活哪个函数
2、在派生类中需要定义与虚函数同名的函数(完全相同:函数类型、函数名、参数个数、参数类型顺序)
3、类的构造函数不能是虚函数。因为虚函数是为了实现多态性,根据不同的对象在运行过程中才决定与哪个函数建立联系,而构造函数在对象创建时自动运行
4、析构函数可以声明为虚函数,且通常都是被声明为虚函数
5、基类的虚函数无论被公有继承多少次,在多级派生中仍然为虚函数(虽然派生类中可以省略virtual,但是为了能一眼辨认,建议不要省略)
6、必须使用基类指针访问虚函数,才能获得运行的多态性。虽然可以使用对象名和点运算符(面向对象的方式)的方式来调用虚函数,但是这种调用是在编译时进行的,是静态联编,不能利用虚函数的好处
1.3、作用:
允许通过基类类型的 指针或引用 来访问派生类中的同名函数。
动态多态引出虚函数 例1 #include<iostream> using namespace std; class Animal { public: //虚函数 父类的virtual必须写 virtual void Speak() //增加了个 virtual { cout<<"动物在说话"<<endl; } }; class Cat : public Animal { public: //重写 函数返回值类型 函数名 参数列表 完全相同 (virtual) void Speak() //对于子类 virtual可写可不写 { cout<<"喵"<<endl; } }; class Dog : public Animal { public: void Speak() { cout<<"汪"<<endl; } }; void doSpeak(Animal &animal) //父类的引用指向子类对象 { animal.Speak(); //这个Speak拥有了多种形态,根据传入的对象不同,来表示调用函 数的不同 } void test() { Cat cat; doSpeak(cat); Dog dog; doSpeak(dog); } int main() { test(); return 0; } 例二: #include<iostream> using namespace std; class B1 { public: virtual void Display() { cout<<"基类B1"<<endl; } }; class B2 { public: virtual void Display() { cout<<"基类B2"<<endl; } }; class B3 : public B1 ,public B2 { void Display() { cout<<"基类B3"<<endl; } }; int main() { B1 *b1,bb1; B2 *b2,bb2; B3 *b3,bb3; b1 = &bb1,b1 -> Display(); b2 = &bb2,b2 -> Display(); b1 = &bb3,b1 -> Display(); b2 = &bb3,b2 -> Display(); return 0; }
2、纯虚函数
2.1、定义:
基类往往表示一种没有具体意义的抽象概念(或表示共性,但后代在共性的基础上又有差异性),即使虚函数在基类中不需要做任何工作,也要写出一个空的函数体。
2.2、语法
virtual 函数返回值类型 虚函数名(参数列表) = 0;
2.3、规则:
1. 纯虚函数是一种没有函数体的特殊虚函数,声明时“= 0” 表示这是这是一个纯虚函数
2. 纯虚函数不能被调用,只能在派生类中具体定义后才可调用
3. 纯虚函数的作用在于基类给派生类提供一个标准的函数模型,统一的接口来实现动态多态,派生类根据需要写出纯虚函数的具体代码
#include<iostream> using namespace std; class Animal { protected: string name; int age; public: Animal(string _name,int _age):name(_name),age(_age){} virtual void Behavior() = 0; }; class Dog:public Animal { public: Dog(string _name,int _age):Animal(_name,_age){} //只能用列表法继承构造函数 void Behavior() { cout<<"修勾名为:"<<name<<endl; cout<<"年龄为:"<<age<<endl; } }; class Cat:public Animal { public: Cat(string _name,int _age):Animal(_name,_age){} void Behavior() { cout<<"修猫名为:"<<name<<endl; cout<<"年龄为:"<<age<<endl; } }; int main() { Dog d1("大黄",3); Cat c1("憨憨",2); Animal *p; //定义父类 对象指针 p = &d1; //指向子类对象 p -> Behavior(); //父类对象指针调用子类函数 p = &c1; p -> Behavior(); return 0; }
二、基础类
1、map
1.1,insert如键值以存在,不更新,返回失败。
更新代码如下:
map<string, int> auto it = m_map.find(name); if(it != m_map.end()) it->second = item; else m_map.insert(make_pair(name, item));
2、vector 与 list区别
vector 拥有一块连续的内存,因此支持随机访问,支持高效率的访问。
list拥有一段不连续的内存空间,支持高效率的插入和删除,而不关心访问效率。