Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有自动存储持续时间的虚拟功能似乎不起作用_C++_Polymorphism_Virtual Functions - Fatal编程技术网

C++ 具有自动存储持续时间的虚拟功能似乎不起作用

C++ 具有自动存储持续时间的虚拟功能似乎不起作用,c++,polymorphism,virtual-functions,C++,Polymorphism,Virtual Functions,我在使用虚拟函数和使用自动存储持续时间声明的对象时遇到问题。以下是一个可复制的场景: #include <iostream> class A { public: A() {} virtual ~A() {} virtual void printClassName() { std::cout << "A" << std::endl; } }; class B :

我在使用虚拟函数和使用自动存储持续时间声明的对象时遇到问题。以下是一个可复制的场景:

#include <iostream>

class A {
    public:
        A() {}
        virtual ~A() {}
        virtual void printClassName() {
            std::cout << "A" << std::endl;
        }
};

class B : public A {
    public:
        B() : A() {}
        ~B() {}
        void printClassName() {
            std::cout << "B" << std::endl;
        }
};

class Test {
    private:
        A item;

    public:
        Test() {}
        ~Test() {}
        void setItem(A item) {
            this->item = item;
        }
        A getItem() {
            return this->item;
        }
};

int main() {
    Test t;
    B item;

    t.setItem(item);
    t.getItem().printClassName();

    return 0;
}
这个打印A,而我希望它打印B。我很好奇为什么

提前谢谢你

这种现象称为对象切片

基本上,当您将类型为B的项传递给采用a的setItem时,您将丢失B的所有信息,因为a B不能存储在a中

所以,当您调用printClassName时,它只从A知道该函数,所以它从A调用它

一种可能的解决方案是向对象传递指针,而不是原始数据。在您的示例中,这将调用B的printClassName,因为没有发生切片。

您在这里:

当您将项传递到setItem时,B部分被切掉,因此您将丢失此项的基本部分。如果一个类是抽象的,这将是一个更明显的错误,因为您不能按值存储抽象类


相反,您将希望将该项存储为指针。

为了清楚起见,为了避免对象切片,在这种情况下,您应该将void setItemA item更改为void setItemA&item,将getItem更改为void setItemA&item 获取项目(&getItem)

这种通过引用传递/返回的方法保留了动态类型,并且几乎可以肯定这是您在本例中想要的

编辑:我忽略了一个事实,即您存储的对象也是类型A。这无法工作。您需要将其作为指针,以便它能够具有与其静态类型或引用不同的动态类型,但随后必须在构造函数中对其进行初始化

所以,若要更改为使用指针,可以尝试将测试中的项更改为*项。然后设置/获取:

    void setItem(A& item) {
        this->item = &item;
    }
    A& getItem() {
        return *(this->item);
    }

这将为您提供所需的输出。如果你只是测试多态行为,这是可以的,但是对于实际的设计需要仔细考虑,例如,你可能想考虑是否应该使用STD::SyrdypTr.< /P>共享所有权,以确保所有非叶基类都是抽象的。否则,使用类可能会非常困难。这可能值得一读:@KerrekSB我尝试将printClassName设置为纯虚拟,但这导致第21行出现编译错误。错误:字段类型“a”是一个抽象类。@ChadJohnson:正确。现在你发现了你的问题。@ChadJohnson:不,你搞错了:你的代码有误解。将基类抽象化暴露了这种误解。因此,这是一种很有用的做法,可以防止像您这样的事故,这种事故可能是由单个字符的打字错误造成的。我将声明更改为void setItemA&item,并且a仍然打印。不幸的是,将getItem更改为a&getItem仍然打印a。问题在于细节。您想将您的项目存储在类型为a的私有变量中,其中仍然发生切片…->这只是问题的一半。你还必须处理一个项目;在类中。@ChadJohnson请注意,如果您不设置项,您有未定义的行为:请看一看,最好将其作为引用添加到构造函数中。因此,内部项始终是有效的对象。
    void setItem(A& item) {
        this->item = &item;
    }
    A& getItem() {
        return *(this->item);
    }