1 虚函数
1.1 定义 用virtual修饰的成员函数叫 虚函数
1.2 对类内存影响
空的类(类内没有数据成员,成员函数不占用内存)占用1字节
有虚函数的占用4字节(32位),也就是一个指针的大小
无论有多少个虚函数都是占用4字节。
类外实现不需要virtual修饰
#include<iostream>
using namespace std;
class A
{
public:
void print() {}
protected:
};
class B
{
public:
virtual void print() {}
protected:
};
void testVitrual()
{
cout << sizeof(B) << endl;
}
void testA()
{
cout << sizeof(A )<< endl;
}
int main()
{
testA();
testVitrual();
return 0;
}
1.3 虚函数表
就是一个指针,存放了所有虚函数的首地址。
#include<iostream>
using namespace std;
class A
{
public:
virtual void print1() {cout<<"虚函数1"<<endl;}
virtual void print2() { cout << "虚函数2" << endl; }
virtual void print3() {}
protected:
};
void testA()
{
A a;
int** vptr = (int**)&a;
typedef void(*PF)();
PF func = (PF)vptr[0][0];
func();
func = (PF)vptr[0][1];
func();
}
int main()
{
testA();
return 0;
}
2 多态
2.1 定义 同一种行为(调用)导致不同 的结果
2.2 必要性原则
必须父类存在虚函数(子类有无virtual都可,但必须有同名函数)
子类必须采用public继承
必须存在指针的引用(使用)
#include <iostream>
using namespace std;
class Man
{
public:
void print1()
{
cout << "阿郎" << endl;
}
virtual void print2() //父类必须要有virtual
{
cout << "阿郎呀呀" << endl;
}
protected:
};
class Sister :public Man
{
public:
void print1()
{
cout << "阿妹" << endl;
}
void print2()
{
cout << "阿妹妹呀" << endl;
}
protected:
};
void testVirtual()
{
//正常访问不存在多态
cout << "正常访问,就近原则" << endl;
Man man;
man.print1();
man.print2();
Sister woman;
woman.print1();
woman.print2();
cout << "指针访问,正常赋值" << endl;
Man* pm = new Man;
pm->print1();
pm->print2();
Sister* pw = new Sister;
pw->print1();
pw->print2();
cout << "指针非正常赋值:子类对象初始化父类指针" << endl;
Man* parent = new Sister;
//有virtual看对象类型,没有virutal看指针
parent->print1(); //不是虚函数
parent->print2(); //是虚函数 调用子类
parent = new Man;
parent->print2(); //调用父类 与51行同种行为 结果不同
}
//统一接口功能呢
void printInfo(Man* parent)
{
parent->print2();
}
int main()
{
testVirtual();
printInfo(new Sister);
return 0;
}
2.3 多态应用
降低因为变化而要修改代码
采用增加代码方式满足新需求
#include <iostream>
using namespace std;
class Shape
{
public:
virtual void Draw()
{
cout << "绘制过程" << endl;
}
protected:
};
class Rect :public Shape
{
public:
void Draw()
{
cout << "画矩形" << endl;
}
protected:
};
class Circle :public Shape
{
public:
void Draw()
{
cout << "画圆" << endl;
}
protected:
};
class Triangle :public Shape
{
public:
void Draw()
{
cout << "绘制三角形" << endl;
}
};
class Ellipse :public Shape
{
public:
void Draw()
{
cout << "绘制椭圆" << endl;
}
};
//降低因为变化而要修改代码
//采用增加代码方式满足新需求
//统一接口
class Tool
{
public:
void draw(Shape* parent)
{
parent->Draw();
}
};
int main()
{
Tool* pTool = new Tool;
pTool->draw(new Circle);
pTool->draw(new Rect);
pTool->draw(new Triangle);
pTool->draw(new Ellipse);
return 0;
}
3 纯虚函数
纯虚函数也是虚函数,只是纯虚函数函数没有函数体
3.1 写法
virtual void print()=0;
3.2抽象类
具备至少一个纯虚函数的类称为抽象类
抽象类不可以构建对象
抽象类可以构造对象指针
所有子类重写函数必须和父类的一模一样
子类想要创建对象必须重写父类的纯虚函数
可以增加别的函数和成员
纯虚函数没有被重写,无论被继承多少次 都是纯虚函数
虚函数无论被继承多少次都是 虚函数
4 虚析构
在用子类对象初始化父类指针,为确保子类对象能被释放,父类的析构需要用virtual修饰
#include<iostream>
using namespace std;
class parent
{
public:
virtual ~parent()
{
cout << "父类析构" << endl;
}
protected:
};
class son :public parent
{
public:
~son()
{
cout << "子类析构" << endl;
}
};
int main()
{
//子类对象初始化父类指针,父类需要虚析构做内存释放
parent* pp = new son;
delete pp; //父类不是虚析构 这是子类无法释放内存;
return 0;
}
5 两个关键字
final 禁止重写
放在 虚函数的后面
子类继承后 不可重写函数,即使到孙子类内 也不可重写
override 强制重写 标识作用
用在子类中 重写父类函数,起到标识作用 如果父类中没有该函数,会报错
用来检查父类中是否存在当前虚函数