一:C++ 虚函数定义
在其他语言中实现多态的基础就是基类中存在抽象方法,然后子类去实现抽象方法从而实现了多态,但是在C++中实现多态遇到了一些问题,首先咱们先看一下虚函数的定义:
/*
抽象基类
*/
class Creature {
private:
string _skill;
public:
string type;
string name;
int age;
Creature() {
cout << "a default creature is created.." << name << age << type << endl;
};
Creature(const string& t,const string& n,const int a): type(t),name(n),age(a) {
cout << "creature was created" << endl;
cout << "type of " << type << " creature was created and it's name is " << name << " age is " << age << endl;
}
~Creature() {
cout << name << " creatrue was deleted" << endl;
}
/* 子类必须继承 纯虚函数不能指向子类对象 */
virtual void eat() = 0;
};
上面的的存虚函数,子类必须实现这个方法
/* 子类必须继承 纯虚函数不能指向子类对象 */
virtual void eat() = 0;
子类中实现:
class Spider : public Creature {
public:
float damage;
Spider() {
name = "spider";
cout << "spider was created" << endl;
}
Spider(const string& t, const string& n, const int a, const float d) : Creature(t, n, a), damage(d) {
cout << "spider's damage si " << damage << endl;
}
void eat() override {
cout << "spider eating " << endl;
}
};
eat()方法后面加入了 override表示重写了父类的方法
二: 多态的实现
其他语言实现多态一般是 P p = new Son() 这种方式来使用,现在在C++语言种是不行的,只能通过指针和引用的方式才可以:
class Dog : public Creature {
public:
Dog() {
cout << "dog was created " << endl;
}
Dog(const string& t, const string n, const int a) : Creature(t, n, a) {
}
~Dog() {
cout << name <<" dog was deleted " << endl;
}
void bark() {
cout << "dog bark" << endl;
}
void eat() override {
cout << "dog eating " << endl;
}
};
void test() {
Dog a("dog","w",4);
// 堆上分配内存,函数调用结束后不会释放内存需要手动释放内存 造成一个问题就是只有Creature类的析构函数被调用了,但是子类的析构函数没有调用,
Creature* creaturePtr = new Dog("dog", "wangcai", 5);
delete creaturePtr;
}
int main() {
/*Spider spider;
*
*
Dog() 是在栈上分配内存,不需要程序员管理内存,对象被销毁的时候,析构函数会自动调用
new Dog() 是在堆上分配内存
Spider spider1("spider1","damageable",3,5.4);*/
test();
Creature* creaturePtr = new Dog("dog", "wangcai", 5);
//delete creaturePtr;
}
但是我想到 Dog dog和 new Dog() 有什么区别呢,查过相关资料才得知,Dog dog的方式的话分配的内存空间是在栈上的,但是Creature* creaturePtr = new Dog(); 分配的空间是在堆上的,那么可以总结一下:
下面是一个表格,总结了Dog()
和new Dog()
在C++中的主要区别:
特性 | Dog() | new Dog() |
---|---|---|
内存分配 | 栈(Stack) | 堆(Heap) |
生命周期 | 自动管理。当对象所在作用域结束时自动销毁。 | 手动管理。需要显式使用delete 来销毁。 |
访问方式 | 直接通过对象访问。 | 通过指针访问。 |
析构函数调用 | 自动调用析构函数以释放资源。 | 使用delete 时自动调用析构函数释放资源。 |
适用场景 | 当对象的使用期限限于一个狭窄的作用域内时。 | 当对象需要跨多个作用域使用,或其生命周期不由单个作用域决定时。 |
资源释放 | 自动。 | 需要手动使用delete 操作符。 |
风险 | 无内存泄漏风险。 | 如果忘记使用delete ,可能会导致内存泄漏。 |
使用Dog()
创建对象时,对象在栈上分配内存,并在其所在的作用域结束时自动销毁。这种方式简单且安全,但是它限制了对象的生命周期。
使用new Dog()
创建对象时,对象在堆上分配内存,并且需要程序员显式地管理对象的生命周期,包括使用delete
来销毁对象以释放资源。这种方式提供了更大的灵活性,但也增加了内存泄漏的风险,如果程序员忘记释放内存,
那么随之而来的还有一个问题就是如果 new Dog()的方式初始化对象的时候,delete操作能不能调用它的析构函数呢,所以才有了test()方法:
void test() {
Dog a("dog","w",4);
// 堆上分配内存,函数调用结束后不会释放内存需要手动释放内存 造成一个问题就是只有Creature类的析构函数被调用了,但是子类的析构函数没有调用,
Creature* creaturePtr = new Dog("dog", "wangcai", 5);
delete creaturePtr;
}
结果只有Creature类调用了析构函数,但是 new Dog指向对象没有销毁,容易造成内存泄漏
三:多态引入的内存泄漏怎么解决呢?
只需要修改一行代码:就是抽象基类的构造方法为虚函数
virtual ~Creature() {
cout << name << " creatrue was deleted" << endl;
}
这样子类删除的时候,会首先调用Dog类的析构函数,再调用Creature类的析构函数。