我有以下课程
//myClass.h
myClass{
int data;
public:
myClass();
void foo1(int);
void foo2();
~myClass();
};
//myClass.cpp
#include"myClass.h"
myClass::foo1(int a){
data = a ;
}
// main
int main(){
myClass m;
m.foo1(10);
}
为什么我们可以有一个非实现的函数(即头文件中的函数原型,但在.cpp文件中没有定义),但不是未实现的默认构造函数或析构函数?
如果我使默认构造函数/析构函数未实现(如上例所示),为什么会出现编译器错误?
当我没有实现构造函数时,我看到undefined reference to myClass::myClass()
,而当我没有实现析构函数时,我看到undefined reference to vtable for myClass
。但是,如果我实现这两个(即使使用空块{}
),并且保留方法(例如foo2()
)未实现,编译器也不会抱怨。
构造函数/析构函数本质上只是类中的方法吗?如果是这样,为什么我有一个未定义的方法foo2()
,但没有未定义的构造函数或析构函数?
如果有人可以帮助我理解这一点(而不只是“因为这就是它的方式”:),那将非常感激。
答案 0 :(得分:4)
如果是这样,为什么我有一个未定义的方法
foo2()
,但没有未定义的构造函数或析构函数?
因为您正在使用构造函数和析构函数,而不是使用foo2()
。添加一个调用,您将收到链接时错误。
答案 1 :(得分:3)
为什么我们可以拥有一个未实现的功能(即功能 标题中的原型,但在.cpp文件中没有定义),但不是 未实现的默认构造函数或析构函数?
你的断言是错误的。您可以拥有未实现的默认构造函数。实际上,这是确保您的类永远不会被隐式构造的一种方法。
如果我保持默认的构造函数/析构函数未实现(比如 上面的例子),为什么我会收到编译器错误?
因为您在代码中的某处使用它。重新读取编译器错误。它可能会告诉你确切的位置。
这就是:
int main(){
myClass m;
m.foo1(10);
行myClass m;
使用默认构造函数实例化myClass
。
如果不使用默认构造函数,则可以声明但不实现默认构造函数并编译清理。考虑:
class Foo
{
public:
Foo (int x) {}
Foo();
};
int main()
{
Foo f (1);
}
这里有Foo()
的声明,但没有实现。代码编译时没有编译器或链接器错误。但是,此代码不会编译干净:
int main()
{
Foo f;
}
后一个例子是你想要做的,在这里:
myClass m;
答案 2 :(得分:1)
编译器只关心你声明的代码(这是你的类声明所做的)。如果您声明构造函数,它会假定您已在某处实现了它。链接器将在您使用它时尝试查找该实现。对于构造函数/析构函数,在尝试创建类的实例时使用它。如果它们不存在,您将收到链接器错误。如果您不使用foo2()
,并且未实现,则链接器不需要找到它,因此它不会尝试。因此,您不会收到链接器错误,您的代码将被成功编译并链接到可执行文件中。
答案 3 :(得分:0)
为什么我们可以有一个未实现的函数(即头文件中的函数原型,但.cpp文件中没有定义),但不是未实现的默认构造函数或析构函数?
必须定义任何使用的函数。如果不使用它们,大多数函数都可以保留未定义。
如果我保留默认构造函数/析构函数未实现(如上例所示),为什么会出现编译错误?
因为你的程序创建并销毁你的类的实例,它使用构造函数和析构函数;因为它们被使用,所以必须对它们进行定义。你已经宣布了它们,所以它们不会被隐含地定义;因此,你必须自己定义它们。
当我没有实现构造函数时,我看到了对myClass :: myClass()的未定义引用;
那是因为构造函数用于创建对象。
和myClass的
vtable
的未定义引用,当我没有实现析构函数时。
这是因为这个编译器在与析构函数相同的转换单元中生成vtable
(如果它既不是隐式也不是内联的)。如果您没有声明析构函数但没有定义它,那么您也不会得到vtable
。
但是,如果我实现这两个(即使使用空块{}),并且保留一个未实现的方法(例如foo2()),编译器也不会抱怨。
那是因为你没有使用这个功能。如果你打电话给它,那你就会收到错误。
构造函数/析构函数本质上只是类中的方法吗?
或多或少,是的;但它们在各方面都很特别。语言规范将它们描述为“特殊成员函数”,并且整章描述了它们的属性。
如果是这样,为什么我有一个未定义的方法
foo2()
,但没有未定义的构造函数或析构函数?
重申:您必须定义您使用的任何内容。如果实例化类,则使用构造函数和析构函数。