1. 程式人生 > >C++中為什麼不允許通過返回型別過載函式的辯論

C++中為什麼不允許通過返回型別過載函式的辯論

2004-07-05 13:25:31 別逗了
問個問題:
1。C++中為什麼不允許通過返回型別過載函式?
2。為什麼不允許通過返回型別解析模板函式?

2004-07-05 14:47:55 完美廢人
返回型別是一種可有可無的東西……

2004-07-05 16:41:23 完美廢人
瞧見什麼叫高手了吧

2004-07-05 18:32:46 別逗了
那operator type()怎麼說?不是根據返回值判斷呼叫那個函式的嗎?

2004-07-05 18:34:49 完美廢人
void f();
int f();
f(); //which one to go?

2004-07-05 18:35:18 別逗了
增加一條規則就是了。

2004-07-05 18:35:27 無鋒之刃
啊哈!

2004-07-05 18:35:31 完美廢人
怎麼描述?

2004-07-05 18:35:53 完美廢人
type-cast operators are individual functions, not the same one with diff return type

2004-07-05 18:39:11 別逗了
void f();
int f();
之間只是存在歧義,當出現歧義的時候,按照C++的習慣,制定一個最佳匹配規則。規則不行的時候,擴充套件語法, 呼叫形式: f() void;或者f() int;

2004-07-05 18:39:37 完美廢人
手工確認呼叫哪個函式?那還要過載幹嗎?

2004-07-05 18:39:44 完美廢人
而且

2004-07-05 18:39:57 無鋒之刃
最佳匹配規則上說你這兩個選擇一樣地好……

2004-07-05 18:39:58 完美廢人
void f() 和 int f();,沒有過載規則可以達到呼叫 void f();

2004-07-05 18:40:13 別逗了
那問題是,可以判別的時候,就不用指定了啊.

2004-07-05 18:40:32 無鋒之刃
那問題是,沒有辦法 判別。

2004-07-05 18:40:39 完美廢人
為了這麼一點方便?我不如直接寫 void f_void(); 和 int f_int(); 算了

2004-07-05 18:41:03 別逗了
那你放到模板裡面怎麼辦?

2004-07-05 18:41:27 完美廢人
拜託了大哥,儘量簡化問題是每個程式設計師應盡的義務

2004-07-05 18:41:43 別逗了
呼叫形式作一個擴充套件不行?例如f() void;

2004-07-05 18:41:57 完美廢人
f() void; 和 f(); 怎麼區別?

2004-07-05 18:42:06 別逗了
指定返回值是void的f().

2004-07-05 18:42:15 完美廢人
我直接 f(); 就會有二義性錯誤

2004-07-05 18:42:21 別逗了
對.

2004-07-05 18:42:23 完美廢人
這樣的語法,還不如不用過載

2004-07-05 18:42:43 無鋒之刃
這是歷史的倒退。

2004-07-05 18:42:52 別逗了
問題是,加了這個,對你以前的過載有影象嗎?

2004-07-05 18:43:11 別逗了
你以前的程式碼規則照樣起作用.

2004-07-05 18:43:57 別逗了
你完全可以不通過返回值過載函式---只有需要的人才會用到這個功能.

2004-07-05 18:44:11 別逗了
為什麼就倒退了?

2004-07-05 18:44:25 完美廢人
struct base
{
  virtual void f();
};
struct d:public base
{
  void f();
  int f();
};
base * p = new d;
p->f(); ??

2004-07-05 18:44:45 無鋒之刃
編譯器無法通過返回型別來判斷應該呼叫哪個函式。連結器也是。

2004-07-05 18:45:20 別逗了
首先,你按照新的規則,定義了一對過載函式,卻指望按照老的方式呼叫,當然不行.

2004-07-05 18:45:49 完美廢人
如果沒有 struct d,我的老規則完全適用

2004-07-05 18:45:51 無鋒之刃
那什麼是新的呼叫方式?

2004-07-05 18:45:52 別逗了
我的意思,增加了新的規則,你的老的過載方式,還是像以前一樣工作.

2004-07-05 18:46:02 完美廢人
除非你規定,所有的 void f(); 都必須改成 f() void; 這樣呼叫

2004-07-05 18:46:07 別逗了
p->f() void;
或者

2004-07-05 18:46:12 別逗了
p->f() int;

2004-07-05 18:46:26 完美廢人
struct S
{
  void f(); //how to call?
};

2004-07-05 18:46:30 無鋒之刃
那我還不如寫p->f_int()呢。搞那麼複雜。

2004-07-05 18:46:41 完美廢人
這個過載完全沒有意義

2004-07-05 18:47:07 別逗了
好,我舉個有意義的例子給你.

2004-07-05 18:48:20 完美廢人
plz

2004-07-05 18:48:27 別逗了
max(T1& lhs, T2& rhs)
{
  //應該返回什麼型別?
}
int i = max(2, 3.3);
double d = max(2, 3.3);
 

2004-07-05 18:48:51 別逗了
這是內部型別,可以互相轉換,如果是自定義型別呢?

2004-07-05 18:49:05 別逗了
max應該返回什麼型別?

2004-07-05 18:49:08 完美廢人
自定義型別怎麼能進行比較?

2004-07-05 18:49:17 完美廢人
如果能比較,就應該能轉化

2004-07-05 18:49:27 別逗了
我的自定義型別定了了less不可以阿?

2004-07-05 18:49:39 完美廢人
你試試看。

2004-07-05 18:51:17 別逗了
例如我定義了dec型別和money型別。返回值需要做轉換,轉換可能丟失精度。如果不需要轉換,那就沒有這個問題。

2004-07-05 18:52:41 完美廢人
所以你有
dec max(const dec &, const money &);

money max(const dec &, const money &): ?

2004-07-05 18:54:00 完美廢人
1、建議你看看 C++0x 的 typeof
2、不論什麼時候,過載決斷是編譯器的,不存在動態聯編,所以根據返回值過載不切實際。

2004-07-05 18:54:21 別逗了
對。我的money型別是定點數,在進行數學運算的時候,有時候需要轉換成dec型別,以防止中間運算過程的精度誤差。算完了,還要轉換回來。

2004-07-05 18:54:30 完美廢人
2、不論什麼時候,過載決斷是編譯器的,不存在動態聯編,所以根據返回值過載不切實際。
 

2004-07-05 18:55:03 別逗了
呵呵,我要的就是決斷是編譯器的。

2004-07-05 18:55:07 完美廢人
這個地方,你不如用 enum 好了。

2004-07-05 18:55:13 完美廢人
抱歉,我是說 union

2004-07-05 18:55:28 別逗了
union和我的問題有啥關係?

2004-07-05 18:55:56 完美廢人
typedef union {dec, money} rt_t;
rt_t max (const money &, const dec &);

2004-07-05 18:56:36 別逗了
靠,這不行的,這可真的執行期判決了。

2004-07-05 18:56:37 完美廢人
對 money 和 dec 設計用 NullObject 作為預設值,可以用來檢查 rt_t 的值

2004-07-05 18:56:50 完美廢人
你不靠執行期決斷,返回值就不存在意義。

2004-07-05 18:57:21 完美廢人
money m;
dec d;
infile >> m >> d;
max(m, d); ??

2004-07-05 18:57:34 別逗了
誰說得?先確定一下,你不反對我要返回不同型別的資料了吧?

2004-07-05 18:57:44 完美廢人
反對。

2004-07-05 18:57:56 完美廢人
強烈反對用 union 這麼變態的東西

2004-07-05 18:58:02 別逗了
好,那一個個問題來。

2004-07-05 18:58:10 benbear
強烈反對廢人此觀點

2004-07-05 18:58:21 別逗了
首先,我才不要返回union 。

2004-07-05 18:58:21 完美廢人
我有一個很好的解決辦法

2004-07-05 18:58:31 完美廢人
想不想聽?

2004-07-05 18:58:38 別逗了
我要返回的就是money或者是dec

2004-07-05 18:58:56 完美廢人
std::pair 作為返回好了,哈哈。

2004-07-05 18:59:43 benbear
你試過
dec max(const dec &, const money &);

money max(const dec &, const money &):
能通過編譯嗎?

2004-07-05 18:59:47 別逗了
一樣沒用。你怎麼知道返回值是什麼型別?返回兩個?那你怎麼知道該用那個?

2004-07-05 19:00:06 完美廢人
把不是返回值的一個指標作為 0

2004-07-05 19:00:17 完美廢人
這是為什麼我用指標而不是引用的原因

2004-07-05 19:00:22 完美廢人
指標有 NullObject

2004-07-05 19:00:26 別逗了
我知道不能,所以我才不滿意C++強加的限制。

2004-07-05 19:01:01 別逗了
越來越垃圾的設計了。[shake]

2004-07-05 19:01:12 完美廢人
總比越來越垃圾的語言好[:D]

2004-07-05 19:01:28 完美廢人
荼毒你一個,幸福俺大家

2004-07-05 19:01:32 別逗了
怎麼垃圾了,我說得新特性你可以不用啊。

2004-07-05 19:01:46 完美廢人
那麼你告訴我,怎麼呼叫 basd::virtual void f(); ??

2004-07-05 19:02:22 完美廢人
我真的可以對一個
void func (base * p)
{
  p->func(); //不是 p->func() void; ?
}

2004-07-05 19:02:47 完美廢人
沒有什麼東西是沒有代價的。

2004-07-05 19:03:21 別逗了
你不是不用嘛,幹嗎要通過返回值過載?只要你不僅僅通過返回值過載(這是現狀),就不必知道新特性。但是,你需要僅僅通過返回值過載,你就需要新特性。

2004-07-05 19:03:41 完美廢人
我當然不用!但是我不能保證從我的類派生的傢伙們不用!

2004-07-05 19:04:07 完美廢人
作為一個介面基類,我必須把一切該死的可能性都考慮進去

2004-07-05 19:04:35 別逗了
OK.那麼,、先確認一點:新特性對既有的程式碼,不需要修改,同意不?

2004-07-05 19:04:52 完美廢人
不同意

2004-07-05 19:05:03 別逗了
那你舉例反對。

2004-07-05 19:05:45 完美廢人
struct Base
{
virtual void fun();
};

void f(const Base * p)
{
  p->fun(); //你要我抄多少遍?
}

2004-07-05 19:07:29 別逗了
很顯然,這是呼叫void fun()啊。現有規則就能解決。如果派生類定義了同名的,而型別不同,那就是同名覆蓋,而不是過載。

2004-07-05 19:08:11 完美廢人
好,某個 newbie 寫了
struct Derived : public Base
{
  virtual void fun();
  virtual int fun();
};
如何??

2004-07-05 19:08:31 別逗了
這個在現有規則下合法嗎?

2004-07-05 19:09:00 完美廢人
我的基類是舊規則的,但是這個 newbie 是學習新規則長大的,如何?舊的程式碼已經不能通用了!

2004-07-05 19:09:48 別逗了
靠,newbie寫的是新程式碼!他既沒有遵守舊規則,也沒有遵守新規則!

2004-07-05 19:10:09 完美廢人
他為什麼沒有遵守新規則?很漂亮的 rt-overload

2004-07-05 19:10:32 別逗了
讓我想想。

2004-07-05 19:11:57 完美廢人
:)恭候。

2004-07-05 19:14:17 別逗了
OK。這裡只能呼叫void fun(),因為,virtual void fun();
  virtual int fun();是兩個函式。而Base當中根本就不認識virtual int fun();所以,你老的程式碼f(const Base * p)
只有一種選擇,就是原來的那一個。
 

2004-07-05 19:14:47 別逗了
所以,這裡沒有任何問題。[:D]

2004-07-05 19:15:05 無鋒之刃
[?]

2004-07-05 19:15:15 完美廢人
呵呵,有道理。

2004-07-05 19:15:28 完美廢人
刀子,替我砍!

2004-07-05 19:15:45 無鋒之刃
你去弄個砧板來

2004-07-05 19:15:48 別逗了
好啊,繼續,我接著。

2004-07-05 19:16:34 完美廢人
那麼,如果 struct Base 放在新規則下,我就必須寫 p->fun() void; 了?

2004-07-05 19:18:12 別逗了
不必。只有在老規則不能分辨的時候才需要這樣寫。
例如:
long f(int);
char f(char);
不需要寫成f(10) int;

2004-07-05 19:19:10 完美廢人
struct Base
{ virtual void fun(); };
struct Derived : public Base
{ virtual int fun(); };
算是隱藏?

2004-07-05 19:19:30 完美廢人
這個在現有模式下是怎麼處理的?

2004-07-05 19:19:33 別逗了
但是也有部分地方會有問題,就是沒有一個是匹配的,但是存在兩個同樣優先順序的轉換時。

2004-07-05 19:19:50 完美廢人
這個從來都存在問題……無奈了

2004-07-05 19:20:03 完美廢人
我上次寫那個 bi_map,都差點放棄過載了

2004-07-05 19:20:37 別逗了
1。現有模式不能只通過返回值區分過載。2。如果你的引數不同,那麼,這兩個函式覆蓋。

2004-07-05 19:21:23 完美廢人
都是 (void) 的時候,發生的是覆蓋、修改介面、還是??

2004-07-05 19:21:34 別逗了
覆蓋。

2004-07-05 19:21:44 別逗了
錯了。

2004-07-05 19:21:50 完美廢人
到底是……?

2004-07-05 19:21:52 別逗了
怎麼都是void?

2004-07-05 19:22:11 完美廢人
int f(void); 和 派生類的 void f(void); 或者相反。

2004-07-05 19:22:21 無鋒之刃
你們在討論蝦米……

2004-07-05 19:22:22 別逗了
是這樣:
覆蓋

2004-07-05 19:22:42 完美廢人
這個東西我是沒法明白了……刀子或者雞丁還有希望:(

2004-07-05 19:22:52 別逗了
倒!

2004-07-05 19:23:01 無鋒之刃
《EC》上說“絕對不要重新定義繼承而來的非虛擬函式”……

2004-07-05 19:23:17 別逗了
是啊。

2004-07-05 19:23:23 完美廢人
struct Base
{ virtual void fun(); };
struct Derived : public Base
{ virtual int fun(); };

2004-07-05 19:23:26 無鋒之刃
那……

2004-07-05 19:23:30 完美廢人
struct Base
{ virtual void fun(); };
struct Derived : public Base
{ virtual int fun(); };

2004-07-05 19:23:30 別逗了
但是,語言則要考慮到。

2004-07-05 19:23:34 完美廢人
兩個函式簽名相同啊,怎麼會是覆蓋的?

2004-07-05 19:24:00 無鋒之刃
返回值型別是不會被Name-mangling機制處理的。

2004-07-05 19:24:18 完美廢人
所以應是一般的派生類重寫而已

2004-07-05 19:24:23 別逗了
暈倒,簽名規則不可以變啊?況且,簽名規則根本就是和編譯沒太大關係得,連線系統關係比較大而以。

2004-07-05 19:24:38 完美廢人
我現在是說傳統 C++……

2004-07-05 19:24:45 無鋒之刃
你把你的想法提交C++ Standard Commitee,也許有可能……

2004-07-05 19:24:46 完美廢人
不瞭解過去就無法預測將來

2004-07-05 19:26:06 別逗了
我好像在那裡看到過說為什麼不能通過返回值過載的,但是,我實在是想不起來任何線索了。

2004-07-05 19:26:24 完美廢人
別逗了:這兩個函式簽名相同,不可能是覆蓋……

2004-07-05 19:26:49 無鋒之刃
也不可能是過載,因為引數列表一樣。

2004-07-05 19:27:05 完美廢人
本來就不可能,因為是在不同的 class scope

2004-07-05 19:27:14 完美廢人
所以只能是重寫了。

2004-07-05 19:27:32 無鋒之刃
重定義。

2004-07-05 19:27:33 別逗了
函式簽名不包括返回值?那dump出來的dll中怎麼解析我的返回值型別的?

2004-07-05 19:27:59 完美廢人
dump 出來的 dll 還支援 const char * 到函式的對映呢……

2004-07-05 19:29:41 別逗了
不要搞,我問你:int CppUnit::CompilerOutputter::wrapColumn(void)
Name-mangling之後怎麼知道返回值是int而不是void的?

2004-07-05 19:29:52 完美廢人
不知道。

2004-07-05 19:30:09 完美廢人
返回值和 name mangling 無關

2004-07-05 19:31:09 別逗了
int CppUnit::CompilerOutputter::wrapColumn(void)
是我用depends從dll中匯出的函式名。
這是C函式名:
[email protected]@[email protected]@QBEHXZ
你是這裡面沒有返回值資訊?

2004-07-05 19:31:29 完美廢人
我沒看到 int 啊

2004-07-05 19:31:44 別逗了
那時你不知道怎麼解碼。

2004-07-05 19:32:11 完美廢人
呵呵:)這是一句沒有說服力的反駁

2004-07-05 19:32:11 無鋒之刃
在C中呼叫C++的函式,要在C++程式碼中使用extern "C"來禁止過載的……

2004-07-05 19:33:05 別逗了
暈倒,我剛才的兩個名字就是同一個,只不過depends能夠[email protected]@[email protected]@QBEHXZ解碼成int CppUnit::CompilerOutputter::wrapColumn(void)這樣可以讀的格式。

2004-07-05 19:33:26 無鋒之刃
那也只是湊巧……

2004-07-05 19:33:36 完美廢人
呵呵~這是用結論逆推理論。

2004-07-05 19:33:58 別逗了
什麼湊巧,C++的dll全都是這樣的,自己可用depends去看。

2004-07-05 19:34:30 無鋒之刃
別在Dll中使用太多過載,不然會死得很慘的。

2004-07-05 19:34:34 別逗了
我的意思是:Name-mangling不過是一種實作手段而以。

2004-07-05 19:34:48 完美廢人
我沒有 depends。逆試試
struct { int f();}
struct { void f();}
有沒有區別

2004-07-05 19:35:07 無鋒之刃
但是為什麼編譯器廠商都沒有把你想的實作出來呢?

2004-07-05 19:35:23 別逗了
你不是用vc的嗎?怎麼沒有depends?

2004-07-05 19:35:29 完美廢人
不知道:(

2004-07-05 19:35:52 別逗了
depends.exe沒有?暈倒!

2004-07-05 19:36:11 完美廢人
好像沒裝 vc-tools 的說……

2004-07-05 19:36:13 無鋒之刃
C++編譯出的Dll在Console下怎麼呼叫?

2004-07-05 19:36:24 完美廢人
LoadLibrary

2004-07-05 19:36:30 別逗了
可以得。

2004-07-05 19:36:33 無鋒之刃
又一個API……

2004-07-05 19:36:40 無鋒之刃
[:8]

2004-07-05 19:36:55 別逗了
C編譯出的dll難道不需要?

2004-07-05 19:37:07 完美廢人
我正在看 CreateRemoteThread,居然被別逗了老兄拉來侃這個……

2004-07-05 19:37:28 別逗了
玩那個幹嗎?

2004-07-05 19:37:41 完美廢人
為了他*媽*的造福人民,除錯病毒用。

2004-07-05 19:38:01 無鋒之刃
傳說中嚐遍百草的廢人……

...