为什么在类中定义的c++成员函数不会产生重复的符号,而在C中却会

Why do C++ member functions defined in a class not produce duplicate symbols, whereas they do in C?

本文关键字:符号 而在 定义 c++ 成员 为什么 函数      更新时间:2023-10-16

C示例

bb.c:

#include "bb.h"
#include <stdio.h>
void bb() {
    printf("aa()...n");
    aa();
}

c:

#include "aa.h"
#include "bb.h"
int main(int argc, const char** argv) {
    aa();
    bb();
    return 0;
}

aa.h:

#ifndef aa_h
#define aa_h
#include <stdio.h>
void aa() {
    printf("aa()...n");
}
#endif // aa_h

bb.h:

#ifndef bb_h
#define bb_h
#include "aa.h"
void bb();
#endif // bb_h
结果C

用clang main.c编译

duplicate symbol _aa in:
    /var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/main-OsFJVB.o
    /var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/bb-OkcMzn.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
c++示例

b.cpp:

#include "b.hpp"
void b::do_something_else() {
    std::cout << "b::do_something_else() being called..." << std::endl;
    a a;
    a.doit();
}

main.cpp:

#include "a.hpp"
#include "b.hpp"
int main() {
    a a;
    b b;
    a.doit();
    b.do_something_else();
    return 0;
}

a.hpp:

#ifndef a_hpp
#define a_hpp
#include <iostream>
class a{
public:
    void doit() {
        std::cout << "a::doit() being called..." << std::endl;
    }
};
#endif // a_hpp

b.hpp:

#ifndef b_hpp
#define b_hpp
#include "a.hpp"
#include <iostream>
class b{
public:
    void do_something_else();
};
#endif // b_hpp
c++结果

上面的代码在clang++ main.cpp b.cpp下可以很好地编译,程序的输出为:

a::doit() being called...
b::do_something_else() being called...
a::doit() being called...

  1. 为什么在c++版本中出现重复错误not ?

  2. 函数void a::doit()在头文件中定义的而不是源文件,这是否意味着编译器将自动内联该函数?

在c++中,类方法不是顶级符号,而是在其类层次结构中有效地限定作用域的名称。

这意味着你已经在c++中定义了两个doit()方法,a::doit()b::doit()

在C语言中,你试图定义一个aa()函数两次。

注意,如果在同一个类的作用域内两次定义doit()方法, c++也会给出错误。
#include <iostream>
class a {
  public:
  void doit() {
    std::cout << "hello" << std::endl;
  }
  void doit() {
    std::cout << "goodbye" << std::endl;
  }
};

导致

ed.cpp:11:8: error: ‘void a::doit()’ cannot be overloaded
   void doit() {
        ^
ed.cpp:7:8: error: with ‘void a::doit()’
   void doit() {
        ^

在您的C示例中,aa被定义了两次,这违反了"一次定义规则"。如果它是C++,这也同样成立。

C++的例子中,a::doit被定义了两次,但是它被隐式地声明为inline。根据[dcl.fct.spec]/3,在类中定义的成员函数是隐式内联的:

在类定义内定义的函数是内联函数. ...

inline函数是每个[basic.def.odr]/5的一个定义规则(实际上,这是标准要求的inline的唯一含义)的例外。

可以有一个以上的…带有外部链接的内联函数(7.1.2)…在一个程序中,如果每个定义出现在不同的翻译单元中,并且提供定义满足以下要求. ...

需求本质上归结为一个需求,即定义在它们出现的每个翻译单元中都是相同的。

如果您将aa声明为inline,则将应用类似的规则,并且您的代码将按照预期编译和工作。

为什么c++版本不会出现重复错误?

因为没有重复。c++成员函数的作用域由定义它们的类决定。B::doit()不是a::doit()的副本。

函数void a::doit()是在头文件而不是源文件中定义的,这是否意味着编译器将自动内联该函数?

相关文章: