[英]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.