基类类型的指针忘记了原始对象类型

Pointer of base class type forgets original object type

本文关键字:类型 原始 对象 忘记了 指针 基类      更新时间:2023-10-16

我有一个指向派生自同一基类的对象的指针向量。问题是在调用函数(而不是方法)时忘记了原始对象的类型。

class Cat{
    //base class
public:
    virtual void growl() = 0;
};
class HouseCat : public Cat{
    //derived class
public:
    void growl(){};
};
class AlleyCat : public Cat{
    //derived class
public:
    void growl(){};
};
void function(HouseCat& a){};
void function(AlleyCat& a){};
int main(){
    vector<Cat*> cats;
    cats.push_back(new HouseCat);
    cats.push_back(new AlleyCat);
    function(*(cats[0])); //error: cannot convert parameter 1 from 'Cat' to 'HouseCat &'
    (cats[0])->growl(); //this works though
}

有解决方法吗?

  • 添加另一个虚拟函数以Cat为(也添加虚拟析构函数):

    class Cat{
       //base class
        ~virtual Cat() {}  //add a virtual destructor as well
         virtual void growl() = 0;
         virtual void call_function() = 0;    
    };
    

    并将其实现为:

    class HouseCat : public Cat{
       //derived class
       virtual void growl(){};
       virtual void call_function() {  function(*this); }
    };
    

    然后你可以这样写:

    cats[0]->call_function();
    

    它最终会调用function()的适当重载。

  • 或者只是在类层次结构中将function实现为虚拟成员函数。

你可以有一个dynamic_cast(我假设你遗漏了virtual并且growl是虚拟的)。

或者你可以function 将参数作为参数 Cat& ,IMO 这是最干净的方法。

每只

家猫都是猫,但每只猫都不是家猫。因此,如果您打算学习多态性(从您的代码中,它看起来像这样),请记住,允许转换为基类指针/引用,从基类指针/引用转换为子类并不容易。您必须显式使用dynamic_cast。

但是,除此之外,您的代码还有许多其他问题。咆哮的方法应该声明为虚拟的,你应该为它指定一个返回类型,你不能从外部调用私有成员函数((cats[0])->growl() 不会编译)。