C++中,实现多态有以下方法:虚函数,抽象类,覆盖,模板(重载和多态无关)。多态也是面对对象编程的关键所在。
和内置指针一样,智能指针类也支持派生类向基类的类型转换,这意味着我们可以将一个派生类对象的指针存储在一个基类的智能指针内。(C++Primer)。
我们先定义一个基类:
class Person
{
public:
string name;
Person(){}
Person(const char* _name){name=_name;}
virtual void show()
{
cout<<name<<" show in Person"<<endl;
}
virtual ~Person(){cout<<name<<" delete in Person\n";}
};
两个派生类:
class PersonA:public Person
{
public:
PersonA(){}
PersonA(const char* _name){name=_name;}
void show()
{
cout<<name<<" show in PersonA"<<endl;
}
virtual ~PersonA(){cout<<name<<" delete in PersonA\n";}
};
class PersonB:public Person
{
public:
PersonB(){}
PersonB(const char* _name){name=_name;}
void show()
{
cout<<name<<" show in PersonB"<<endl;
}
virtual ~PersonB(){cout<<name<<" delete in PersonB\n";}
};
1.普通派生类的使用:
int main()
{
Person person("小明");
person.show();
PersonB person2("小李");
person2.show();
PersonA person3("小张");
person3.show();
return 0;
}
运行结果:
可以看出,分别生成了三个类,程序退出的时候,都调用了析构函数,删除了三个对象。因为PersonA和PersonB是Person的派生类,所以析构的时候回调用基类Person的析构函数。
2.内置指针的使用:
int main()
{
Person* person = new Person("小明");
person->show();
person = new PersonA("小李");
person->show();
person = new PersonB("小张");
person->show();
return 0;
}
运行结果:
- 可以看出,使用new生成的对象,在程序结束的时候也没有调用析构函数,这个和C++中的内存保存地址有关,之前的例子,对象的地址保存在栈中,这个内存不需要我们手动分配,当然删除这个内存也不需要我们,所以编译器会在程序结束的时候,自动调用析构函数,把栈中的对象清空。
- 但是,这里我们使用的是new,申请的对象的地址是保存在堆中,需要我们手动申请空间,当然,删除这个空间也需要我们手动删除。但是我们没有在程序的最后进行删除对象,所以最后没有调用析构函数,这样很容易造成内存泄漏。但是,一个对象何时删除,这是一个比较麻烦的事情。
- 所以我们可以使用智能指针累,来帮我们手动删除对象。
3.使用智能指针
int main()
{
shared_ptr<Person> person = make_shared<Person>("小明");
person->show();
person = make_shared<PersonA>("小李");
person->show();
person = make_shared<PersonB>("小张");
person->show();
return 0;
}
运行结果:
现在我们发现,当智能指针person在指向其他对象的时候,之前的对象就调用析构函数,删除了指针对象的地址。同时在程序结束的时候,再次析构了当前对象。我们使用智能指针,我们可以不用考虑什么时候删除对象,会自动帮我们删除对象,类似于自动使用垃圾回收。