0

关于多态对象成员的问题,我昨天得到了一个优雅的答案。

但是现在我面临一个问题,即变量的行为并没有像我预期的那样。正在使用以下代码:

#include <iostream>
#include <math.h>

using std::cin;
using std::cout;
using std::endl;


class Com
{
    public:
        virtual void setReady()
        {
            cout << "Com" << endl;
        }
};

class DerivedCom : public Com
{
    public:
        void setReady()
        {
            cout << "DCom" << endl;
        }

        void somethingElse()
        {
            cout << "else" << endl;
        }

};

class BaseClass
{
    public:
        Com* com;

    public:
        BaseClass(Com* c = new Com) : com(c)
        {
        }

        virtual void setReady()
        {
            com->setReady();
        }
};

class DerivedClass : public BaseClass
{
    // the call to somethingElse() won't compile if I leave out this declaration
    protected:
        DerivedCom* com;

    public:
        DerivedClass() : BaseClass(new DerivedCom) 
        {
        }

        void setReady()
        {
            // This line causes a segfault if I put in the declaration earlier
            this->com->setReady();

            // This line won't compile if I leave out the declaration earlier
            this->com->somethingElse();
        }
};

int main()
{
    DerivedClass* inst = new DerivedClass();

    inst->setReady();
    return 0;
}

问题是,这DerivedClass::com实际上是类型DerivedCom,但我无法访问任何DerivedCom特定的方法,因为编译器找不到它们。如果我添加额外的重新声明DerivedCom* com,编译器会找到方法,但会出现分段错误。

4

2 回答 2

3

删除那个额外的声明。

如果你确定 aCom*是 aDerivedCom*那么你就可以static_cast了。

static_cast<DerivedCom*>(this->com)->somethingElse();

但是,如果您错了,这可能会崩溃。因此,如果您不确定,那么您dynamic_cast可以

DerivedCom* dcom = dynamic_cast<DerivedCom*>(this->com);
if (dcom)
    dcom->somethingElse();

dynamic_cast如果对象不是您要求的类型,将返回 NULL。

于 2012-11-20T13:48:22.663 回答
0

分段错误的原因是您没有使用不同的类型再次声明变量,您实际上是在派生类中定义了一个新指针,一个从未初始化的指针。因此this->com->...将访问派生类com并崩溃,因为它是一个未初始化的指针

但是,您要做的是更改成员指针的类型。您可以通过将成员指针的类型设置为模板变量来做到这一点,如下所示

template <class ComType>
class BaseClassTemplate
{
    ComType* com;
    ...;
};

typedef BaseClassTemplate<Com> BaseClass;

class DerivedClass : public BaseClassTemplate<DerivedCom>
{
    ...;
};

但是,这使基类成为模板,因此要按您的意愿获取它,您需要进行实例化BaseClass<Com>以获取您的基类版本。正如我所展示的,您可以将其设为派生类或仅作为 typedef。

于 2012-11-20T14:06:48.107 回答