什么情况下用多态
多态是面向对象编程中的一个重要概念,可以提高代码的可扩展性和可维护性。在以下情况下,可以考虑使用多态:
当有一个基类或接口,并且存在多个具体的子类或实现类时,可以使用多态来统一处理这些不同的子类或实现类对象。
当需要对多个对象执行相同的操作时,可以使用多态来简化代码,提高代码的可读性和可维护性。
当需要根据不同的条件来执行不同的操作时,可以使用多态来实现条件分支的逻辑。
当需要在运行时动态地确定对象的类型时,可以使用多态来实现。
当你需要以一种统一的方式处理不同类型的对象时,可以使用多态。
总之,多态可以使代码更加灵活、可扩展和可维护,并能提高代码的可读性和可靠性。它是面向对象编程中的一个重要概念,应该在合适的情况下加以应用。
例子
对于游戏装备,不同的装备对于一个游戏角色有不同的作用效果,这些装备类就可以通过多态实现对于游戏角色的不同作用效果
对于交通工具,如果要让他们启动,不同的交通工具他们自身的启动的方式是不同的,这些交通工具类就可以通过多态实现
构造和析构的顺序
在C++中,对象的构造和析构的顺序是按照继承关系顺序进行的。具体来说,构造函数的执行顺序是从基类到派生类,而析构函数的执行顺序则是从派生类到基类。
举个例子,假设有如下的继承关系:
class Base {
public:
Base() {
cout << "Base constructor" << endl;
}
~Base() {
cout << "Base destructor" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived constructor" << endl;
}
~Derived() {
cout << "Derived destructor" << endl;
}
};
当创建一个派生类对象时,构造函数和析构函数的执行顺序如下:
调用基类的构造函数(Base constructor)
调用派生类的构造函数(Derived constructor)
执行派生类的构造函数内的代码
调用派生类的析构函数(Derived destructor)
调用基类的析构函数(Base destructor)
可以看到,构造函数从基类到派生类依次执行,而析构函数则是从派生类到基类依次执行。这个顺序的原因是为了确保在构造函数期间,所有的父类对象都已经创建,而在析构函数期间,先销毁派生类对象的成员,再销毁基类对象。
为什么要把析构函数声明为虚函数
在C++中,当一个类中包含有虚函数时,通常还需要将析构函数声明为虚函数。这是因为当使用基类指针指向派生类对象,并通过该指针调用delete运算符时,只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类对象中申请的资源无法被正确释放,可能会引发内存泄漏的问题。
通过在析构函数前加上virtual关键字,可以解决这个问题。这样,当通过基类指针删除派生类对象时,会首先调用派生类的析构函数,然后再调用基类的析构函数,确保派生类对象中的资源得到正确释放。
示例代码如下:
class Base {
public:
virtual ~Base() {
// 基类析构函数的实现
}
};
class Derived : public Base {
public:
virtual ~Derived() {
// 派生类析构函数的实现
}
};
int main() {
Base* p = new Derived();
delete p; // 通过基类指针删除派生类对象
return 0;
}
在上面的示例代码中,基类Base的析构函数使用virtual关键字进行了声明。这样,在执行delete p语句时,会首先调用派生类Derived的析构函数,然后再调用基类Base的析构函数,确保派生类对象中的资源得到正确释放。
为什么不能在构造函数和析构函数中使用虚函数
在构造函数和析构函数中调用虚函数是一个容易出错的做法,并且它可能导致意想不到的行为。这是因为在构造函数和析构函数期间,对象的状态可能不完全或已经改变,并且虚函数的行为可能取决于对象的状态。
在构造函数中调用虚函数可能会导致以下问题:
虚函数的实现依赖于派生类中的成员变量,而在构造函数中,这些成员变量可能尚未被初始化,因此虚函数可能无法按预期工作。
构造函数的执行顺序是从基类到派生类,因此在构造函数期间,派生类的成员可能尚未初始化,这可能导致虚函数的行为不一致或错误。
在基类的构造函数中调用虚函数时,实际调用的是基类的虚函数,而不是派生类的虚函数,这可能导致多态性失效。
在析构函数中调用虚函数也可能导致以下问题:
调用虚函数时,派生类的数据成员可能已经被销毁,因此虚函数可能无法访问正确的数据。
在析构函数期间,对象已经进入析构状态,因此调用虚函数可能导致未定义的行为。
为避免这些问题,通常建议避免在构造函数和析构函数中调用虚函数。如果需要在对象创建和销毁期间执行特定的操作,可以考虑使用非虚函数或将这些操作放在其他地方进行处理。
本人尝试基类构造函数中调用虚函数会导致崩溃和错误,但是如果在最高级的派生类构造函数里调用虚函数,就不会有问题,此时派生类已经完成初始化,并且调用的是自身的虚函数。
如何让基类能够获取派生类中的数据
如果是通过父类指针访问派生类里的数据,可以使用下面的办法,在父类中定义缓存变量,子类中对变量写入数值
class Base {
...
protected:
int buff;
};
class Derived : public Base {
...
public:
void update() {
Base::buff = xxx;
}
};
...
Base *p = new Derived;
p->get_buff();
也可以通过虚函数间接的访问派生类变量