下面简单的代码。
class Base{
public:
int fcn();
};
int main() {
Base b; // clause 1
}
Run Code Online (Sandbox Code Playgroud)
为什么会这样编译?第 1 条创建了一个实例,但从未定义Base该函数。fcn()
原因Base b;不是编译器错误,而是因为编译器一般无法知道是否缺少定义。
您发布的代码可能是完整的翻译单元,而定义位于不同的翻译单元中。只有当需要定义(例如调用函数)但找不到定义时,链接器才会发出错误。
实际上,在很多情况下,人们希望声明某些内容但不定义(或仅有条件地定义)。下面是两个例子。
假设您有一个带有参数的方法double,并且您希望阻止用户使用int. 隐式转换可能很烦人,基本类型的隐式转换更令人烦恼。人们可以做这样的事情:
struct foo {
void do_something(double) {}
};
struct bar {
void do_something(double) {}
void do_something(int); // no definition !!
};
int main()
{
foo{}.do_something(1);
bar{}.do_something(1);
}
Run Code Online (Sandbox Code Playgroud)
foo::do_something(double)可以用int. 另一方面,bar::do_something(double)必须bar::do_something(int)在重载解析中竞争并bar{}.do_something(1);导致链接器错误。
请注意,这里有更好的方法来获取更好的编译器错误消息(= delete自 C++11 以来)。然而,重点是:只要你只bar::do_something用doubleall 跟注就可以了。没有错误。并且不会出现任何错误。它可以工作并且是完全有效的 C++。
另一个例子是用于区分模板的不同实例的标签类型:
struct tag1; // no definition !!
struct tag2; // no defniition !!
template <typename T> struct foo;
template <> struct foo<tag1> { /* something */ };
template <> struct foo<tag2> { /* something else */ };
int main() {
foo<tag1> a;
foo<tag2> b;
}
Run Code Online (Sandbox Code Playgroud)
这完全没问题,因为模板不会执行任何要求其参数为完整类型的操作。仅使用类型来标记模板的实例或选择重载是一种常见技术,有时标记所需的只是一个声明。
补充一下,这与您的示例不同,因为它缺少整个类定义,并且没有创建类的实例。尽管我会把它放在同一个包中:对于没有定义的声明很有用。
| 归档时间: |
|
| 查看次数: |
116 次 |
| 最近记录: |