我教了一个C++编程类,我已经看到了足够多的错误类型,我对如何诊断常见的C++错误感觉很好.但是,有一种主要类型的错误,我的直觉并不是特别好:编程错误导致调用纯虚函数? 我见过的最常见的错误导致这是从基类构造函数或析构函数调用虚函数.在帮助调试学生代码时,还有其他我应该注意的事项吗?
在本讲座中,发言者提到(一开始)标准库中没有纯虚函数(或者他没有注意到).我相信Alex Stepanov反对这种语言功能但是从最初的STL设计开始,是否有任何纯粹的虚拟内容进入标准库?
FWIW(并纠正我,如果我错了)唯一指针中的删除器最终在大多数实现中使用虚拟调度,但这些不是纯虚拟.
c++ virtual-functions pure-virtual c++-standard-library language-lawyer
错误在这里:
vector<Graduate *> graduates;
graduates.push_back(new AliceUniversity(identifier,id,salary,average));
Run Code Online (Sandbox Code Playgroud)
祖父母班:
Graduate::Graduate(char identifier,
long id,
int salary,
double average)
: _identifier(identifier),
_id(id),_salary(salary),
_average(average)
{
}
Run Code Online (Sandbox Code Playgroud)
家长班:
UniversityGraduate::UniversityGraduate(char identifier,
long id,
int salary,
double average)
: Graduate(identifier,id,salary,average)
{
}
Run Code Online (Sandbox Code Playgroud)
实际/儿童班:
AliceUniversity::AliceUniversity(char identifier,
long id,
int salary,
double average)
: UniversityGraduate(identifier,id,salary,average)
{
_graduateNum++;
_sumOfGrades += average;
_avrA = getAverage();
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一个很长的镜头,我不能在这里写完整个代码......
在C++中,给出纯虚函数的实现是合法的:
class C
{
public:
virtual int f() = 0;
};
int C::f()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
你为什么要这样做?
相关问题:C++ faq lite包含一个例子:
class Funct {
public:
virtual int doit(int x) = 0;
virtual ~Funct() = 0;
};
inline Funct::~Funct() { } // defined even though it's pure virtual; it's faster this way; trust me
Run Code Online (Sandbox Code Playgroud)
我不明白为什么析构函数被声明为纯虚拟然后实现; 我不明白为什么这应该更快的评论.
所以这是我所在的框.我想了解为什么在你的接口类中有一个"虚拟析构函数"很重要.如果你可以挂到最后,你会看到为什么那些东西在引号中...我也想让所有的词汇绝对正确.到目前为止,这是我处理过程的地方:
有时您有基类,有时您有从基类继承的派生类.
如果你有一个基指针,它发现自己指向一个派生对象,你还希望从该指针指向一个派生对象的成员函数调用,就像它实际上被调用一样从派生对象中,您调用的成员函数最好在基类中声明为virtual.
接口是任何只有纯虚函数的类.如果从此接口类派生新类并实现所有纯虚函数,则最终可以创建派生类的实例.
你永远不可能有一个接口类的实例,但你可以有一个指向接口类的实例.
如果你有一个实际指向派生类对象的指针接口类(实际上,我想如果#4是正确的话,它总是必须这样),如果你决定通过它删除那个对象你的指针,如果你的接口类中没有"虚拟析构函数",你破坏派生对象的意图只会作为一个调用来执行,以破坏基础对象(即接口类),因为没有虚拟析构函数,事物永远不会达到实际调用派生对象的析构函数的程度 - 从而导致内存泄漏.
唷.好的,如果这听起来是正确的,请回答我的问题.仅仅在你的界面中声明一个虚拟析构函数就足够了:
virtual ~iFace();
Run Code Online (Sandbox Code Playgroud)
这对我来说是错误的......所以如果你像这样使析构函数变为虚拟,会发生什么:
virtual ~iFace() = 0;
Run Code Online (Sandbox Code Playgroud)
既然它们只是声明,那么它们中的任何一个都算是"接口类中的虚拟析构函数"吗?你甚至可以有一个声明但未定义的析构函数吗?只有它是纯粹的虚拟我猜...
无论如何,所以回到标题问题......我真的要尽可能快......这是拍摄的钱......如果你的"界面类中的虚拟析构函数"需要至少一个像这样的空定义:
virtual ~iFace() {};
Run Code Online (Sandbox Code Playgroud)
那个成员函数不是纯虚拟的(不能因为你给了它一个定义),因此你的类不再是一个接口(它不仅包含纯虚拟成员函数).
这意味着如果为接口定义虚拟析构函数,则不再具有接口(而只是一些抽象基类).这只是滥用语言吗?我明白发生了什么吗?
注意:这一切都来自于问自己"什么是界面?" 然后阅读这个问题的答案: 你如何在C++中声明一个接口?
希望漫长的骑行时间不会太长,但我决心完全理解这些概念及其相关的词汇.
我有三个类:B,D和G. D是一个B,G是一个D.这两个B和D是抽象的. B来自第三方.
B有一个非纯的虚方法G需要实现(成为a D).将虚拟函数重新定义/覆盖为纯虚拟,我可以并且是一种好习惯吗?
例:
class B // from a third party
{
public:
virtual void foo();
};
class D : public B
{
public:
void foo() override = 0; // allowed by gcc 4.8.2
virtual void bar() = 0;
};
class G : public D
{
public:
// forgot to reimplement foo
void bar() …Run Code Online (Sandbox Code Playgroud) 以下代码编译了广泛的gcc和clang版本 - 在编译并使用gcc 5.3.1运行时,它会打印出来
一个()
然后以纯虚拟调用错误中止.
#include <stdio.h>
class A
{
public:
A() {
printf("A()\n");
}
virtual void b() const = 0;
};
int main()
{
const A& a{};
a.b();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我意识到绑定对临时的引用并不理想(虽然我认为这种情况被某种生命周期扩展所覆盖) - 但它也适用于尝试调用一个带有const引用的方法,如:
Foo({});
Run Code Online (Sandbox Code Playgroud)
为方便起见,这里是一个用clang 3.2 编译的例子:Compiler Explorer
我现在正在课堂上学习C++,而且我不太熟悉纯虚函数.我知道它们稍后在派生类中概述,但是如果你要在派生类中定义它,为什么要将它声明为等于0?
请考虑以下标准CRTP示例:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
Run Code Online (Sandbox Code Playgroud)
如果这是常规虚拟继承,我可以将虚拟f和g方法标记为纯粹
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
Run Code Online (Sandbox Code Playgroud)
并获得关于Foo抽象的编译时错误.但是CRTP没有提供这样的保护.我可以以某种方式实现它吗?运行时检查也是可以接受的.我想过将this->f指针与比较static_cast<Derived …
当编译器具有纯析构Child class函数时,编译器不强制实现析构函数.Basevirtual
struct Base
{
virtual void foo () = 0;
virtual ~Base() = 0;
};
Base::~Base() {} // necessary
struct Child : Base
{
void foo() {}
//ok! no destructor needed to create objects of 'Child'
};
Run Code Online (Sandbox Code Playgroud)
有趣的是那个; 编译器而不是强制Base定义析构函数体.这是理解的.(演示供参考)
那么在课堂上拥有纯粹的析构函数的目的是什么?(它只是禁止创建对象吗?)virtualBaseBase
c++ ×10
pure-virtual ×10
c++11 ×1
clang ×1
crtp ×1
destructor ×1
gcc ×1
interface ×1
performance ×1
terminology ×1
vector ×1
virtual ×1