未定义与已删除与未声明的函数

undefined vs. deleted vs. undeclared function

本文关键字:函数 未声明 删除 未定义      更新时间:2023-10-16

我在这里使用默认构造函数作为示例,但同样的问题适用于所有特殊成员函数。

此外,我正在使用 https://en.cppreference.com 而不是标准,因为这是我正在阅读的内容,这就是我难以理解的内容。如果使用标准会以任何方式改变问题,请告诉我。


如 https://en.cppreference.com/w/cpp/language/default_constructor 中所述,如果一个类没有构造函数,那么编译器将始终声明一个默认构造函数。然后,如果不满足某些条件,它将未定义(在 c++11 之前)或定义为已删除(在 c++11 之后)。

所有这些似乎都暗示着函数未声明、声明但未定义或声明和删除之间存在差异。但是,所有三个选项都不会编译/链接,例如

class MyClass {
public:
void foo();
void bar() = delete;
};
int main() {
MyClass c;
//c.foo();  // won't link
//c.bar();  // won't compile
//c.baz();  // won't compile
}

那么,为什么将定义从"声明和未定义"更改为"声明和删除"如此重要,为什么不首先将其保留为"未声明"呢?

那么,为什么将定义从"声明和未定义"更改为"声明和删除"如此重要

因为差异:"不会链接">"不会编译"。这是引入= delete的根本原因:在编译时而不是以后捕获使用(以前)未定义函数的错误。此外,它允许更好的错误诊断,因为编译器将能够描述删除函数的原因。链接器可以说的最好的是,由于某种未知的原因,没有人定义它。

没有理由不利用隐式生成的成员函数的功能。

= deleted;声明在各种情况下都很有用。除了 eerorika 给出的很好的理由外,它还可用于显式声明给定的"特殊"函数(例如默认构造函数)不存在,并且无法调用。

它还可用于指定基类中存在的函数在派生类中不存在(默认情况下,派生类中不存在)。

下面是一段显示这种用法的简短代码:

#include <iostream>
class foo {
private:
int m;
public:
foo() = delete; // Other programmers reading this definition will know immediately!
foo(int n) : m{ n } {} // ... that default ctor is intended not to be used
void inc() { ++m; }    // ... rather than it has been omitted accidentally
int get() { return m; }
};
class bar : public foo {
public:
bar() : foo(0) {}
void inc() = delete; // Without this, code like `bar b; b.inc();` will call foo.inc()
};
int main() {
//  foo f1; // error C2280: 'foo::foo(void)': attempting to reference a deleted function
foo f2(3); std::cout << f2.get() << std::endl;
f2.inc();  std::cout << f2.get() << std::endl;
bar b1;    std::cout << b1.get() << std::endl;
//  b1.inc(); error C2280: 'void bar::inc(void)': attempting to reference a deleted function
return 0;
}