繁体   English   中英

如果要从另一个翻译单元链接某个成员函数,为什么不能在该类中定义该成员函数?

[英]Why can I not define a member function in a class if that function is to be linked from another translation unit?

我是C ++的新手,但是我偶然发现了以下内容。

如果我有这些文件:

myclass.hpp:

class myclass {
public:
  myclass();
  void barf();
};

mymain.cpp:

#include "myclass.hpp"

int main() {
  myclass m;
  m.barf();
  return 0;
}

我使用myclass的此实现:

myclassA.cpp:

#include <iostream>

using namespace std;

class myclass {   // or include myclass.hpp, it both works fine
public:
  myclass();
  void barf();
};

myclass::myclass() { } //empty
void myclass::barf() {
  cout << "barfing\n";
}

那一切都OK。 但是,如果我使用myclass的这种实现,除了成员是在类定义中定义的之外,这是完全相同的,则会出现链接错误:

myclassB.cpp:

#include <iostream>

using namespace std;

class myclass {
public:
  myclass() { }
  void barf() {
    cout << "barfing\n";
  }
};

我得到的错误:

$ g++ myclassB.cpp mymain.cpp
/tmp/cc4DTnDl.o: In function `main':
mymain.cpp:(.text+0xd): undefined reference to `myclass::myclass()'
mymain.cpp:(.text+0x16): undefined reference to `myclass::barf()'
collect2: ld returned 1 exit status

显然,从myclassB.cpp构建的目标文件不会导出成员函数。 为什么这两种实现方式都不相同? C ++中是否有一些陷阱规则说类定义内的成员定义不是全局可见的,但是如果它们在类外定义则是全局可见的?

表示必须对类,模板等进行唯一定义的标准以某种更为复杂和微妙的方式表达。 该规则通常称为“一个定义规则”,即ODR。 也就是说,当且仅当[1]它们出现在不同的翻译单元中并且[2]它们是tokenforken相同,并且[3]时,才接受类,模板或内联函数的两个定义作为同一唯一定义的示例。这些标记的含义在两个翻译单元中都相同。

例如(有效):

// file1.c:
struct S { int a ; char b ; };
void f(S* p){ }   
// file2.c:
struct S { int a ; char b ; };
void f(S* p){ }  

违反ODR的示例:

file1.c:
struct S 1 { int a ; char b ; };
struct S 1 { int a ; char b ; }; // error: double definition
This is an error because a struct may not be defined twice in a single 
translation unit.

// file1.c:
struct S 2 { int a ; char b ; };
// file2.c:

struct S 2 { int a ; char b b ; }; // error.
This is an error because S2 is used to name classes that differ in a member name.

// file1.c:
typedef int X ;
struct S 3 { X a ; char b ; };
// file2.c:
typedef char X ;
struct S 3 { X a ; char b ; }; // error.
Here the two definitions of S3 are    
token for token identical, but the example is an error because the
meaning of the name X has sneakily been made to differ in the two files.

内联定义的成员函数是编译器要内联的候选函数。 如果从不使用它,而仅在源文件中内联定义,则我怀疑您的编译器将完全删除该方法。

话虽如此,我强烈建议您将声明放在头文件中,而在.cpp文件中仅包含定义。 包括头文件(带有适当的防护,例如#pragma once#idfef/#define防护。随着项目变大,您将需要执行此操作,因此最好立即构建适当的做法。

除了Jagannaths的答案,我还认为myclass.hpp中myclass的定义算作一个声明,但是在C ++中,它是一个定义,因此Jagannaths的答案适用。 事实证明,可以只声明一个类,但是您只能使用指向该类的指针或引用,而不能以任何方式访问它的成员。 另请参见: 在当前翻译单元中声明C ++类而不对其进行定义

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM