C++ 多态成员变量

C++ 多态成员变量,c++,segmentation-fault,polymorphism,C++,Segmentation Fault,Polymorphism,我昨天得到了一个关于我的问题的优雅的答案 但现在我面临的问题是,变量的行为并不是我所期望的那样。正在使用以下代码: #include <iostream> #include <math.h> using std::cin; using std::cout; using std::endl; class Com { public: virtual void setReady() { cout <&l

我昨天得到了一个关于我的问题的优雅的答案

但现在我面临的问题是,变量的行为并不是我所期望的那样。正在使用以下代码:

#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;
}
#包括
#包括
使用std::cin;
使用std::cout;
使用std::endl;
类Com
{
公众:
虚拟void setReady()
{
cout setReady();
返回0;
}

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

删除该extr声明

如果您确定
Com*
DerivedCom*
的,那么您可以
static\u cast

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

如果对象不是您要求的类型,
dynamic\u cast
将返回NULL。

删除该额外声明

如果您确定
Com*
DerivedCom*
的,那么您可以
static\u cast

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

dynamic\u cast
如果对象不是您要求的类型,将返回NULL。

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

但是,您要做的是更改成员指针的类型。。您可以通过将成员指针的类型设置为模板变量来执行此操作,如下所示

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

typedef BaseClassTemplate<Com> BaseClass;

class DerivedClass : public BaseClassTemplate<DerivedCom>
{
    ...;
};
模板
类BaseClassTemplate
{
ComType*com;
...;
};
typedef基类模板基类;
类DerivedClass:公共BaseClassTemplate
{
...;
};

然而,这使得基类成为一个模板,因此,要想获得所需的基类,您需要实例化
BaseClass
以获得您的基类版本。您可以将其设置为派生类,也可以将其设置为typedef,如我所示。

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

但是,您要做的是更改成员指针的类型。。您可以通过将成员指针的类型设置为模板变量来执行此操作,如下所示

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

typedef BaseClassTemplate<Com> BaseClass;

class DerivedClass : public BaseClassTemplate<DerivedCom>
{
    ...;
};
模板
类BaseClassTemplate
{
ComType*com;
...;
};
typedef基类模板基类;
类DerivedClass:公共BaseClassTemplate
{
...;
};


然而,这使得基类成为一个模板,所以要想得到你想要的,你需要实例化
BaseClass
来得到你的基类版本。你可以把它变成一个派生类,或者像我所展示的那样仅仅是一个typedef。

它工作得很好,很有趣!有没有办法只进行一次静态转换,然后简单地使用
这个->com
在类的其余部分中?不,您正在创建的静态强制转换指针是本地范围的。您必须保留该重新声明才能在类中的所有位置使用此->com确保只声明一个成员变量(但称为与
com
不同的名称)然后在构造函数中初始化它。但是我想我宁愿每次都静态地抛出它,复制信息是不好的。比如…声明
DerivedCom*com
并在构造函数中执行
this->com=static\u cast(BaseClass::com);
。或者这只是一个丑陋的黑客行为吗?如果你拥有代码,你也可以添加一个存根(空主体)对基类的
somethingElse()
实现,或声明
somethingElse()
在基类中是纯虚拟的。这很有效,很有趣!有没有办法进行一次静态强制转换,然后在类的其余部分简单地使用
this->com
?没有,您正在进行的静态强制转换指针是本地范围的。您必须保留该重新声明才能在类中的所有位置使用此->com确保只声明一个member变量(但调用了与
com
不同的东西)并在构造函数中对其进行初始化。但我想我宁愿每次都静态地调用它,复制信息是不好的。例如…声明
DerivedCom*com
并执行
this->com=static\u cast(BaseClass::com)
在构造函数中。或者这只是一个丑陋的黑客行为?如果您拥有代码,您还可以将
somethingElse()
的存根(空体)实现添加到基类中,或者声明
somethingElse()
基类中的纯虚拟。在这段代码中,我看不到虚拟dtor,如果在基类上调用delete时需要级联dtor调用,这是必不可少的。这只是一个概念证明。我想我不需要dtors.well,[多态性]标记,至少不需要
virtual~Com{}
看起来很奇怪。@NilsWerner:这已经在原始问题的评论中提到了(特别是问题的第三条评论)。在这段代码中,我没有看到虚拟dtor,如果在基类上调用delete时需要级联dtor调用,这是必不可少的。这只是一个概念证明。我想我不需要dtor。嗯,[多态性]标记,至少不需要
virtual~Com{}
看起来很奇怪。@NilsWerner:这已经在原始问题的评论中提到了(特别是问题的第三条评论)。