如果只定義這個方法,它將會有一個編譯器錯誤。爲什麼必須在C++類定義中聲明一個方法?
void classA::testMethod() {
}
所以它必須首先聲明:
class classA {
void testMethod();
};
爲什麼這些聲明?
我知道它是不是需要申報常見的C方法的方法,但是他們可以定義爲:
void test() {
}
如果只定義這個方法,它將會有一個編譯器錯誤。爲什麼必須在C++類定義中聲明一個方法?
void classA::testMethod() {
}
所以它必須首先聲明:
class classA {
void testMethod();
};
爲什麼這些聲明?
我知道它是不是需要申報常見的C方法的方法,但是他們可以定義爲:
void test() {
}
有幾個次要的原因客觀和主觀(即允許指定可見性,作爲類的接口,可能還有其他幾個與編譯和鏈接階段和TU符號有關的其他原因的可見性,更不用提一類是基本封裝單元,與所有的暗示),但不容置疑之一是的標準規定它:
N3797 - class.mfct/P2
甲成員函數可以在i中定義(8.4) ts類的定義,在 這種情況下它是內聯成員函數(7.1.2),或者它可能是在其類定義之外定義的 ,如果它已經聲明瞭但未在其類定義中定義的 。在類定義之外出現的成員函數 定義應在包含類定義的名稱空間範圍中出現 。除類別定義以外的成員 功能定義和 類別 類別的成員函數的顯式特殊化和成員函數模板(14.7)出現在類別定義之外的 以外,不應重新聲明成員函數。
強調我的。
不用擔心,謝謝你解決這個問題! – 2014-09-26 12:15:00
它有助於封裝。如果你有一個A級
class A {
public:
foo();
bar();
}
你可以肯定,只有方法foo
和bar
惹類的私有數據成員。 (或指針魔術或當然未定義的行爲)
我不明白這是如何相關的。 – user2864740 2014-09-26 09:01:14
@ user2864740可以定義獨立的'void classA :: testMethod(){...}'表示您想要擴展該類。但在C++中情況並非如此。 – Csq 2014-09-26 09:03:33
封裝與這些有什麼關係? C++ *可能被定義爲執行一些愚蠢的魔術,例如將這些找到的定義提升爲類定義(這沒什麼意義,特別是鑑於定義通常與實現分離)。但這些都與封裝無關。 – user2864740 2014-09-26 09:06:22
why should declare these? I know for common c method, there is no need to declare, instead of it just define it:
有一個在C,一個結構的只是屬性沒有方法,至極可以是功能Pointeur,然後關聯到一個功能addresse。
而且必須聲明它的類定義爲你做它在C同樣的原因:
的compilateur將改變這種預申報成一個函數pointeur再聯想到上述梅索德INT的建設你的對象。
如果一個C的定義++類應該被轉換成C結構的代碼會是這樣:
struct Aclass {
void (*Amethode))(int);
}
void Amethode(int) { return (0); }
Aclass primaryObject = {&Amethode};
Aclass* AclassConstructor() {
Aclass* object;
object = malloc(sizeof(Aclass));
memcpy(object, primaryObject, sizeof(Aclass));
return (object);
}
你是否聲稱在C++中的成員函數是通過函數指針屬性來實現的?事實並非如此。成員函數是由編譯器靜態定義和靜態解析的。函數指針在使用虛擬函數時進入它,但採用與我認爲你描述的方式不同的方式。 – 2014-09-26 09:07:23
@Magnus Hoff事實上,你是對的,事實並非如此,但對於一個首次亮相的程序員來說,它更容易理解,或者我認爲是這樣...... – CollioTV 2014-09-26 09:11:00
雖然你所描述的方案可行,但它並不代表實際發生的事情因此令人困惑。我認爲以下幾點更容易理解,除了更接近地表示實際發生的情況外:http://ideone.com/4xhr8T – 2014-09-26 09:15:14
你並不需要你定義它之前聲明的方法,但是你需要在類中聲明類方法。否則它不會是一個類方法。
這似乎是一個矛盾,但定義也是一個聲明。所以,這是什麼意思是,這一定義可能出現在類本身:
class A {
void testMethod() { /*...*/ }
};
[編輯] 此外,實際而言,類聲明中有private
,protected
和public
部分。這是封裝所必需的。如果你可以在類之外聲明方法,你將失去封裝。任何人都可以通過定義額外的獲取者和設置者來訪問私有成員,即使這些成員沒有意義。類不變量將變得毫無意義。
@TonyD你不會降低其他問題以獲得另一個答案,這是你的個人意見,而其他人可能會不同意。現在我明白誰也低估了我的回答。如果答案是錯誤/無用的,那麼你的意圖就是失望,如果你覺得有一個更好的或者你最喜歡的答案,那麼你的意圖就會降低。 – 2014-09-26 10:02:22
「如果你能在課堂外聲明方法,你將失去封裝。」當然,你可以通過在Java的每個方法定義上允許訪問修飾符來解決這個問題。 – 2014-09-27 08:21:26
「方法」或「成員函數」(正如C++中更常見的術語)是類聲明的一部分。既然你必須在一個地方聲明一個C++類,你必須確保所有的「成員函數」(或「方法」)已經存在於該聲明中。
我知道它是不是需要申報常見的C方法的方法,但是當你是指C++中的「常見的C法」,他們 正好可以定義
,實際上指的是「共同功能」。請注意,您可以在任何聲明此類函數的地方聲明類。
此外,請注意,您可以聲明一個正文的成員函數。您不必單獨聲明和定義。即這是完全有效的:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
請注意使用限定符::
。這意味着
所以寫void A::testMethod()
假設有一個類或名稱空間A
定義 - 這是如何定義C++。這適用於
void A::testMethod();
以及爲
void A::testMethod()
{
}
另外請注意,你必須確實沒有在::
左側爲
void ::testMethod()
{
}
根據定義的全局命名空間全局名稱空間總是被定義的,所以上面的代碼定義了一個類似於沒有限定符的C風格的函數。
即使它沒有被標準強制規定,爲什麼需要在類定義中聲明所有的類方法還有以下兩個原因。
您只能在類聲明中聲明爲public,private或protected,但不能在.cpp文件的方法定義中這樣做。那麼你的獨立式課堂方法有什麼可見性?
如果標準決定選擇其中一個作爲默認值(C++默認爲私有),並將該可見性放在您的方法上,則您現在有一個範圍問題。即使是最嚴格的可見性(私有),也意味着您可以在任何其他成員方法中使用該方法,包括在源文件之前定義的那些成員方法。如果沒有類定義中的聲明,那些早期的函數將不會意識到您的自由站立方法,因此您違反了範圍規則。
在你的了foo.h頭:
class foo
{
public:
foo() {}
virtual ~foo() {}
declaredMethod();
};
在你Foo.cpp中
foo::declaredMethod()
{
...
freeStandingMethod(); // This should be legal, but it can't work since we
// haven't seen foo::freeStandingMethod() yet
...
}
foo::freeStandingMethod()
{
...
}
即使你能在同一個.cpp文件這項工作,是合法的將foo::freeStandingMethod()
放在與foo::declaredMethod()
不同的.cpp文件中,此時這變得不可能。
這不是一個答案,但你可能會發現它的信息和樂趣。 添加2個模板功能,你的類將有效地讓你調用任何自由函數,它這個類的一個對象作爲第一個參數:
#include <string>
#include <iostream>
struct puppy {
puppy(std::string name)
: _name(std::move(name))
{}
const std::string& name() const noexcept {
return _name;
}
void set_name(std::string name) {
_name = std::move(name);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args) const
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args)
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
private:
std::string _name;
};
void woof(const puppy& p) {
std::cout << "puppy " << p.name() << " woofs!" << std::endl;
}
void indented_woof(const puppy&p, size_t indent) {
std::cout << std::string(indent, ' ');
woof(p);
}
void complex_woof(const puppy& p, int woofs)
{
std::cout << "attention!" << std::endl;
for (int i = 0 ; i < woofs ; ++i) {
p.perform(indented_woof, 4);
}
}
std::string name_change(puppy& p, std::string(new_name))
{
auto old_name = p.name();
p.set_name(std::move(new_name));
return old_name;
}
int main()
{
puppy fido { "fido" };
fido.perform(woof);
fido.perform(complex_woof, 10);
auto old_name = fido.perform(name_change, "bonzo");
fido.perform(woof);
std::cout << "changed name from " << old_name << std::endl;
return 0;
}
回答(現在刪除)的評論: 執行的一個版本必須是const以支持採用非常量小狗&的函數。 – 2014-09-26 11:15:30
以前所有的答案是正確的,只要他們去,但他們沒有指出規則背後的原因。在C++中, 類定義已關閉;你以後不能添加它。這個 對於非靜態數據成員是必需的,因爲它們決定了大小(以及隱式生成的特殊函數) ,但它是C++中所有類成員的基本原則:不僅僅是 數據,而是函數,類型,對於 好封裝被認爲是必不可少的。
對於支持類概念的大多數(但不是全部)語言都是如此。
這也解釋了爲什麼它的情況不同於 名稱空間(它們沒有關閉)。
+1(早期),但公平性「以前的所有答案」,除Csq's外。 – 2014-09-26 11:16:27
你可以在c中聲明類之外的函數 – jonynz 2014-09-26 09:01:09
@jonynz:這沒有意義,C沒有類或方法。 – MSalters 2014-09-26 09:06:04
採取了一點,謝謝 – jonynz 2014-09-26 09:07:34