提问人:Eris 提问时间:7/25/2022 最后编辑:Vlad from MoscowEris 更新时间:7/25/2022 访问量:90
纯虚拟成员有什么好处吗(除了他们可能防止的人为错误)?
Are there any advantages to pure virtual members (except the human error that they might prevent)?
问:
我有一堆带有纯虚拟成员的类,它将由派生的非抽象类填充。我收到错误:
Error C2259 'ABC': cannot instantiate abstract class TEMP c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\xmemory0 879
这个错误可以通过使用 来解决,但是堆内存访问比堆栈内存慢,所以我正在考虑重写根本没有纯虚拟成员的基类 ABC。stack<ABC*>
这有什么缺点吗(除了可能使用此代码的人可能的人为错误)?
有没有办法在堆栈上创建具有纯虚拟成员的类堆栈?或者,也许,我对使用堆太偏执了?该类(在原始代码中)将被非常频繁地访问。
代码的简化版本如下:
#include <iostream>
#include <stack>
class ABC {
public:
ABC(int& a) : m_a(a) {}
~ABC() {}
virtual void do_something() = 0;
int m_a;
};
class DEF : public ABC {
public:
DEF(int& a) : ABC(a) {}
void do_something() override;
~DEF() {}
};
void DEF::do_something() {
std::cout << "Hi!\n";
}
int main(int argc, char* argv[]) {
int x = 123;
std::stack<ABC> s;
s.push(DEF(x));
}
答:
1赞
Vlad from Moscow
7/25/2022
#1
在此通话中
s.push(DEF(x));
该类型的临时对象将隐式转换为 类型的对象。因此,如果要调用虚函数,则将调用类 ABC 的虚函数。DEF
ABC
在使用指针或引用时,可以使用多态性。
这是您更新的程序。
#include <iostream>
#include <stack>
class ABC {
public:
ABC(int& a) : m_a(a) {}
~ABC() {}
virtual void do_something()
{
std::cout << "Bye!\n";
};
int m_a;
};
class DEF : public ABC {
public:
DEF(int& a) : ABC(a) {}
void do_something() override;
~DEF() {}
};
void DEF::do_something() {
std::cout << "Hi!\n";
}
int main()
{
int x = 123;
std::stack<ABC> s;
s.push(DEF(x));
s.top().do_something();
}
程序输出为
Bye!
正如你所看到的,有对象切片。
请注意,您需要使析构函数成为虚拟的。你可以只在基类中编写
virtual ~ABC() = default;
评论
0赞
Unmitigated
7/25/2022
应该注意的是,析构函数也应该是虚拟的。
1赞
Vlad from Moscow
7/25/2022
@Unmitigated 一句好话。我已经附上了答案。
0赞
SoronelHaetir
7/25/2022
#2
您不能拥有具有虚拟成员(纯成员或非虚拟成员)的对象容器(堆栈就是一个示例)并保持动态行为。您可以有一个指向此类对象的指针容器并维护动态行为,但不能保留此类对象本身。
使用纯虚拟的时候是基类根本没有合理的实现可用的时候。想想像流缓冲区这样的标准类型,基数只是定义一个接口,但基数实际上对许多操作没有任何作用。只有派生类型知道它应该做什么。
评论
std::stack
virtual
std::stack<ABC> s;
-- 这在内部使用 ,它使用堆。std::deque