当 class 包含虚方法时,为什么 clang 会创建这些隐式方法?
Why does clang create these implicit methods when a class contains a virtual method?
我正在开发一个基于 clang 的 AST 的工具,我很好奇为什么 clang 会这样工作。
这是我的意见。我有一个非常简单的 class 定义如下:
class Foo {
int foo();
};
然后在我的 RecursiveASTVisitor 中,我的代码如下所示:
bool MyASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl *D) {
for (auto const & method : D->methods()) {
llvm::outs() << method->getQualifiedNameAsString() << "(";
for (auto const & param : method->params())
llvm::outs() << param->getType().getAsString() << ", ";
llvm::outs() << ")";
if (method->isImplicit())
llvm::outs() << " [implicit]";
llvm::outs() << "\n";
}
return true;
}
这一切所做的就是吐出在所有被访问的 classes 中定义的方法列表。输出如我们所料:
Foo::foo()
现在,让我们对 Foo class 做一个小改动。让我们将 foo() 方法设为虚拟方法:
class Foo {
virtual int foo();
};
现在我的输出改变了:
Foo::foo()
Foo::operator=(const class Foo &, ) [implicit]
Foo::~Foo() [implicit]
我的问题是,为什么向 class 添加虚方法会导致 clang 创建隐式赋值运算符和析构函数?如果我添加 --std=c++11,它也会创建一个隐式移动赋值运算符。这是 clang 的实现细节,还是 C++ 标准的一部分?
原来我应该只读一下 clang 源代码。 SemaDeclCXX.cpp
有一个名为 Sema::AddImplicitlyDeclaredMembersToClass
的方法。关于为什么声明隐式复制赋值有评论:
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
// it shows up in the right place in the vtable and that we diagnose
// problems with the implicit exception specification.
if (ClassDecl->isDynamicClass() ||
ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
这样做是为了确保隐式定义的方法(可能是虚拟的)最终位于 vtable 中的正确位置。
我正在开发一个基于 clang 的 AST 的工具,我很好奇为什么 clang 会这样工作。
这是我的意见。我有一个非常简单的 class 定义如下:
class Foo {
int foo();
};
然后在我的 RecursiveASTVisitor 中,我的代码如下所示:
bool MyASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl *D) {
for (auto const & method : D->methods()) {
llvm::outs() << method->getQualifiedNameAsString() << "(";
for (auto const & param : method->params())
llvm::outs() << param->getType().getAsString() << ", ";
llvm::outs() << ")";
if (method->isImplicit())
llvm::outs() << " [implicit]";
llvm::outs() << "\n";
}
return true;
}
这一切所做的就是吐出在所有被访问的 classes 中定义的方法列表。输出如我们所料:
Foo::foo()
现在,让我们对 Foo class 做一个小改动。让我们将 foo() 方法设为虚拟方法:
class Foo {
virtual int foo();
};
现在我的输出改变了:
Foo::foo()
Foo::operator=(const class Foo &, ) [implicit]
Foo::~Foo() [implicit]
我的问题是,为什么向 class 添加虚方法会导致 clang 创建隐式赋值运算符和析构函数?如果我添加 --std=c++11,它也会创建一个隐式移动赋值运算符。这是 clang 的实现细节,还是 C++ 标准的一部分?
原来我应该只读一下 clang 源代码。 SemaDeclCXX.cpp
有一个名为 Sema::AddImplicitlyDeclaredMembersToClass
的方法。关于为什么声明隐式复制赋值有评论:
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
// it shows up in the right place in the vtable and that we diagnose
// problems with the implicit exception specification.
if (ClassDecl->isDynamicClass() ||
ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
这样做是为了确保隐式定义的方法(可能是虚拟的)最终位于 vtable 中的正确位置。