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);
}