C++中的继承

Inheritance in C++

本文关键字:继承 C++      更新时间:2023-10-16

这是我的问题:我在 .h 文件中定义了一个虚拟方法,我想在从基类继承的类中调用它。 遗憾的是,派生类中的方法没有被调用。有没有更好的方法来实现我正在尝试做的事情?

#ifndef ofxBASE_SND_OBJ
#define ofxBASE_SND_OBJ
#include "ofConstants.h"
class ofxBaseSndObj {
public:
    virtual string getType(){}
    string key;
};
#endif

这是我的嗡嗡声课

#ifndef OFXSO_BUZZ
#define OFXSO_BUZZ
#include "ofxBaseSndObj.h"
class ofxSOBuzz : public ofxBaseSndObj
{
public:
    string getType();
};
#endif

ofxSOBuzz.cpp

string ofxSOBuzz::getType()
{
    string s = string("ofxSOBuzz");
    printf(" ********* returning string type %s", s.c_str()); // doesn't get called!
    return s;
}

然后在另一堂课上,我试着这样称呼它:

string ofxSndObj::createFilter(ofxBaseSndObj obj)
{
    string str = obj.getType();
    if(str.compare("ofxSOBuzz") == 0)
    {
        printf(" all is well ");
    }
}

在上面的方法中,我需要能够传入许多对象之一,这些对象都扩展了ofxBaseSndObj对象。任何建议或指示将不胜感激。谢谢!

更改此行:

string ofxSndObj::createFilter(ofxBaseSndObj obj)

string ofxSndObj::createFilter(ofxBaseSndObj& obj)

您正在做的是按值传递(传递副本)。

这意味着您正在将对象复制到函数中。因为函数不知道你实际传递的类型,所以它只传递函数声明中定义的类型,因此它会复制基类(这称为切片问题)。

解决方案是通过引用传递。

如果您不希望函数修改对象(也许这就是您按值传递的原因,因此它无法更改原始值),则传递 const 引用。

class ofxBaseSndObj
{
    public:
        virtual string getType()  const;
        // If the method does not change the object mark it const
        string key;
};
string ofxSndObj::createFilter(ofxBaseSndObj const& obj)
{
    // allowed to call this if getType() is a const
    string str = obj.getType();
    if(str.compare("ofxSOBuzz") == 0)
    {
        printf(" all is well ");
    }
}

您需要将实例传递给 createFilter 作为指向对象的指针(或引用)。 您是按值传递的,这会导致编译器将用作参数的派生对象复制到基类的实例中。 当它这样做时,您将失去它最初是派生类型的事实。

正如所写的那样,您的代码实际上不应该编译,因为 ofxBaseSndObj::getType 的声明不会返回任何内容。 您的意思是将其作为抽象方法还是返回空字符串?

如果你把它做成一个抽象方法,那么编译器会抱怨试图在你的ofxSndObj::createFilter方法中实例化一个抽象类。

这个问题

在C++中称为"切片"。

将复制构造函数和运算符=设为私有是防止此错误再次发生的有效方法。

例如:

class ofxBaseSndObj {
public:
    virtual string getType(){}
    string key;
private:
    ofxBaseSndObj(const ofxBaseSndObj& rhs);
    ofxBaseSndObj& operator=(const ofxBaseSndObj& rhs);
};

如果没有其他充分的理由,您应该使用RTTI内置的C++。然后可以使用类型标识运算符。如果默认情况下未打开此功能,请查看编译器文档以将其打开。

其他人已经解决了切片问题。 然后你问 好吧,让我说,我知道我需要做一些事情来确定基类型,但是还有什么比做枚举查找来确定继承对象的类型更优雅的吗?

查询和切换对象的类型是一个糟糕的设计,它错过了 OO 方法的重点。

而不是

string ofxSndObj::createFilter(ofxBaseSndObj& obj)
{
    string str = obj.getType();
    if(str.compare("ofxSOBuzz") == 0)
    {
        // do ofxSOBuzz - specific thing
    }
    else if(str.compare("some other derived class") == 0)
    {
        // do stuff for other derived classes
    }
       // etc...
}

使有趣的行为成为虚拟函数:

class ofxBaseSndObj {
public:
    // get rid of getType()
    virtual void HelpCreateFilter() = 0;
};

string ofxSndObj::createFilter(ofxBaseSndObj& obj)
{
    // Let the derived class do it's own specialized work.
    // This function doesn't need to know what it is.
    obj.HelpCreateFilter();
    // rest of filter creation
}

为什么这比原始版本更好? 因为如果将来将 ofxBaseSndObj 的派生类添加到系统中,则不需要修改ofxSndObj::createFilter。 您的版本需要针对每个新的派生类进行扩展。 如果不清楚,请尝试发布更多代码 - 我无法从您的代码或类名中看出这些函数应该做什么。

您可以使用

dynamic_cast或type_id