纯虚函数
语法:
virtual 返回值类型 函数名(参数列表) = 0
纯虚函数的作用:
不用定义!
在多态中,通常父类中虚函数的实现是无意义的(因为主要用子类重写的,父类只是为了派生子类当做一个类族的顶层出现),所以可以将虚函数改为纯虚函数。
抽象类:有纯虚函数的类叫做抽象类
纯虚函数的特点:无法实例化对象,子类必须重写抽象类中的纯虚函数,否则子类也属于纯虚函数(参考上一条)
抽象类 不能定义对象,但是可以定义抽象类的指针或者引用。
用抽象类指针创建子类对象
class Shape
{
public:
virtual void Area() = 0;
virtual void Perimeter() = 0;
};
class Triangle :public Shape
{
public:
void Area() { cout << "T area" << endl; }
void Perimeter() { cout << "T per" << endl; }
Triangle(int l) :m_long(l) {}
private:
int m_long;
};
class Circle :public Shape
{
public:
virtual void Area() { cout << "Ci area" << endl; }
virtual void Perimeter() { cout << "Ci per" << endl; }
Circle(int r) :m_r(r) {}
private:
int m_r;
};
class Rectangle :public Shape
{
public:
virtual void Area() { cout << "Re area" << endl; }
virtual void Perimeter() { cout << "Re per" << endl; }
Rectangle(int l, int w) :m_length(l), m_width(w) {}
private:
int m_length;
int m_width;
};
void test(Shape& sh)
{
sh.Area();
sh.Perimeter();
}
int main11()
{//使用抽象类指针创建其子类
Shape* p[3];// = { new Rectangle(3,5),new Circle(5),new Triangle(6) };
//Shape sh;//err不允许使用抽象类类型
int i;
p[0] = new Rectangle(2, 4);
p[1] = new Circle(5);
p[2] = new Triangle(6);
for (i = 0; i < 3; ++i)
{
p[i]->Area();
p[i]->Perimeter();
delete p[i];
p[i] = NULL;
}
return 0;
}
虚析构和纯虚析构
使用多态时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
此时需要将父类中的析构函数改为虚析构或者纯虚析构。
作用:虚析构和纯虚析构都是用来解决通过父类指针释放子类对象;
如果子类没有堆区数据,可以不写纯虚析构或虚析构;
有纯虚析构的类也属于抽象类;
class Animal
{
public:
Animal() { cout << "Animal构造" << endl; }
~Animal(){ cout << "Animal析构" << endl; }
//纯虚析构_纯虚需要声明也需要定义(代码实现)
//virtual ~Animal() = 0;
virtual void speak() = 0;
};
//Animal:: ~Animal(){ cout << "Animal纯虚析构" << endl; }//在外面定义
class Cat :public Animal
{
public:
Cat(string name)
{
cout << "Cat构造" << endl;
m_Name = new string(name);//子类成员在堆区开辟空间
}
virtual void speak()
{
cout << *m_Name<<" cat speak" << endl;
}
~Cat()
{
cout << "Cat析构" << endl;
if (m_Name != NULL)
delete m_Name;
m_Name = NULL;
}
string* m_Name;
};
int main()
{
Animal* an = new Cat("Mimi");
an->speak();//cat speak
delete an;//父类指针析构时不调用子类中的析构,可能发生内存泄漏
//父类析构函数不是虚析构时,如果释放指向子类的父类指针,只会调用父类的析构函数
//在父类析构函数前面加上virtual关键字就可以解决这个问题
}
不用虚析构的结果:无法调用子类的析构。
在父类析构前加上虚关键字就可以: