具有自动存储持续时间的虚拟功能似乎不起作用
Virtual functions with automatic storage duration does not seem to work
我在对使用自动存储持续时间声明的对象使用虚函数时遇到问题。这是一个可重现的场景:
#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。我很好奇为什么。
提前致谢!
这种现象称为对象切片。
基本上,当您将 item
(B
类型)传递给 setItem
(需要 A
)时,您将失去 B
的每个条信息,因为B
不能存储在A
.
中
所以,当你调用 printClassName
时,它只知道来自 A
的那个函数,所以它从 A
.
调用它
一种可能的解决方案是传递指向对象的指针,而不是原始数据。这将在您的示例中调用 B
的 printClassName
,因为没有发生切片。
您 slicing 在这里:
void setItem(A item) {
this->item = item;
}
当您将 item
传递给 setItem()
时,B
部分被切掉,因此您将丢失其基础部分。如果 A
是抽象的,这将是一个更明显的错误(因为您不能按值存储抽象 class)。
相反,您需要将项目存储为指针。
为了清楚起见,在这种情况下要避免对象切片,您应该将 void setItem(A item)
更改为 void setItem(A& item)
并将 A getItem()
更改为
A& getItem()
。
这(passing/returning 通过引用)保留了动态类型并且几乎可以肯定这就是您在这种情况下想要的
编辑: 我忽略了一个事实,即您存储的对象也是 A
类型。这行不通。您需要将它作为指针,以便它能够具有与其静态类型(或引用,但随后必须在构造函数中初始化)不同的动态类型。
所以要更改为使用指针,您可以尝试将 Test
中的 A item
更改为 A* item
。然后set/get变成:
void setItem(A& item) {
this->item = &item;
}
A& getItem() {
return *(this->item);
}
这为您提供了所需的输出。如果您只是测试多态行为,这没问题,但在实际设计中需要非常小心(例如,您可能想考虑是否应该使用 std::shared_ptr
共享所有权)。
我在对使用自动存储持续时间声明的对象使用虚函数时遇到问题。这是一个可重现的场景:
#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。我很好奇为什么。
提前致谢!
这种现象称为对象切片。
基本上,当您将 item
(B
类型)传递给 setItem
(需要 A
)时,您将失去 B
的每个条信息,因为B
不能存储在A
.
所以,当你调用 printClassName
时,它只知道来自 A
的那个函数,所以它从 A
.
一种可能的解决方案是传递指向对象的指针,而不是原始数据。这将在您的示例中调用 B
的 printClassName
,因为没有发生切片。
您 slicing 在这里:
void setItem(A item) {
this->item = item;
}
当您将 item
传递给 setItem()
时,B
部分被切掉,因此您将丢失其基础部分。如果 A
是抽象的,这将是一个更明显的错误(因为您不能按值存储抽象 class)。
相反,您需要将项目存储为指针。
为了清楚起见,在这种情况下要避免对象切片,您应该将 void setItem(A item)
更改为 void setItem(A& item)
并将 A getItem()
更改为
A& getItem()
。
这(passing/returning 通过引用)保留了动态类型并且几乎可以肯定这就是您在这种情况下想要的
编辑: 我忽略了一个事实,即您存储的对象也是 A
类型。这行不通。您需要将它作为指针,以便它能够具有与其静态类型(或引用,但随后必须在构造函数中初始化)不同的动态类型。
所以要更改为使用指针,您可以尝试将 Test
中的 A item
更改为 A* item
。然后set/get变成:
void setItem(A& item) {
this->item = &item;
}
A& getItem() {
return *(this->item);
}
这为您提供了所需的输出。如果您只是测试多态行为,这没问题,但在实际设计中需要非常小心(例如,您可能想考虑是否应该使用 std::shared_ptr
共享所有权)。