簡體   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