एक ही प्रकार के दो क्‍लॉसेस का उपयोग क्‍यों कर रहे हैं जो कि जीसीसी में अस्पष्ट के रूप में देखा जाता है


32

क्लॉस का उपयोग करने के साथ मेरे पास दो आधार कक्षाएं हैं

 class MultiCmdQueueCallback {
  using NetworkPacket  = Networking::NetworkPacket;
  ....
 }


 class PlcMsgFactoryImplCallback {
   using NetworkPacket = Networking::NetworkPacket;
  ....
 }

मैं तब एक वर्ग घोषित करता हूं

class PlcNetwork : 
  public RouterCallback, 
  public PlcMsgFactoryImplCallback, 
  public MultiCmdQueueCallback {
  private:
    void sendNetworkPacket(const NetworkPacket &pdu);
}

संकलक फिर 'NetworkPacket' के संदर्भ में त्रुटि का संकेत देता है जो अस्पष्ट है 'sendNetworkPacket (NetworkPacket and ...')

अब दोनों एक ही अंतर्निहित क्लास नेटवर्किंग के लिए 'क्लॉस का उपयोग' का संकल्प लेते हैं: NetworkPacket

और वास्तव में अगर मैं विधि घोषणा को प्रतिस्थापित करता हूं:

 void sendNetworkPacket(const Networking::NetworkPacket &pdu);

यह ठीक संकलन करता है।

कंपाइलर प्रत्येक क्‍लॉज का उपयोग करते हुए क्‍लॉज को एक अलग प्रकार का मानता है, भले ही वे दोनों एक ही अंतर्निहित प्रकार की ओर इशारा करते हों। क्या यह मानक द्वारा अनिवार्य है या हमारे पास कंपाइलर बग है?


यह संकलक नहीं चालाक पर्याप्त लगता है
इदरिस

इस बिंदु पर संकलक होने वाले बिंदु को बस यह पता है कि NetworkPacketNetworkC में PlcMsgFactoryImplCallback में, MultiCmdQueueCallback में तीन मौजूद हैं । जो उपयोग करने के लिए निर्दिष्ट किया जाना चाहिए। और मैं नहीं सोचताvirtual से कोई मदद मिलने वाली है।
द वियरेब्रो

@idris: इसके बजाय, आपका मतलब था कि मानक पर्याप्त अनुमति नहीं है। संकलक मानक का पालन करने के लिए सही हैं।
Jarod42

@ Jarod42 नीचे उत्तर में 'टाइप-आईडी द्वारा दर्शाए गए प्रकार का पर्यायवाची' इसलिए यदि उनके पास एक ही प्रकार-आईडी है तो इसे दोनों का उपयोग करने की अनुमति दी जा सकती है। चाहे वह standart हो या कंपाइलर, ऐसा लगता है कि कोई वास्तव में पर्याप्त चतुर नहीं है।
मूर्ख

मल्टी-इनहेरिटेंस की समस्याओं में से एक
ईगल 275

जवाबों:


28

उपनाम परिणाम देखने से पहले, (और पहुंच)

हम नामों पर गौर करते हैं

और सचमुच में,

NetworkPacket हो सकता है

  • MultiCmdQueueCallback::NetworkPacket
  • या PlcMsgFactoryImplCallback::NetworkPacket

तथ्य यह है कि वे दोनों इंगित करते हैं Networking::NetworkPacketअप्रासंगिक है।

हम पहले नाम संकल्प करते हैं, जिसके परिणामस्वरूप अस्पष्टता होती है।


वास्तव में यह केवल आंशिक रूप से सच है अगर मैं PlcNetwork का उपयोग करता हूं: | NetworkPacket = MultiCmdQueueCallback :: NetworkPacket का उपयोग करना; मुझे एक संकलक त्रुटि मिलती है क्योंकि पिछले का उपयोग करते हुए खंड निजी है।
एंड्रयू गोएदरट

@AndrewGoedhart विरोधाभास नहीं। नाम की खोज पहली कक्षा में शुरू होती है। संकलक के रूप में तब एक अनूठा नाम पहले से ही वहां मिल जाता है, यह संतुष्ट है।
एकांकागुआ

यहाँ मेरी समस्या यह है कि आधार वर्ग में एक निजी नामकरण खंड से प्रचार क्यों नाम है। अगर मैं निजी घोषणाओं में से एक को हटा देता हूं, तो आधार कक्षाओं में से एक में क्लॉज का उपयोग करने वाला एक निजी है और दूसरा कोई नहीं, 'नेटवर्क पैकेट में त्रुटि का नाम नहीं है'
एंड्रयू गोएदरट

1
@AndrewGoedhart नाम लुकअप (जाहिर है) एक्सेसिबिलिटी पर विचार नहीं करता है। यदि आप एक सार्वजनिक और अन्य एक निजी बनाते हैं तो आपको वही त्रुटि मिलती है। यह खोज की जाने वाली पहली त्रुटि है, इसलिए यह मुद्रित होने वाली पहली त्रुटि है। यदि आप एक अन्य उपनाम हटाते हैं, तो अस्पष्टता की समस्या दूर हो जाती है, लेकिन एक अक्षमता बनी हुई है, इसलिए आपको अगली त्रुटि मुद्रित होती है। वैसे, एक अच्छा त्रुटि संदेश नहीं (MSVC एक बार फिर?), GCC के बारे में अधिक सटीक है error: [...] is private within this context:।
एकनकागुआ

1
@AndrewGoedhart निम्नलिखित पर विचार करें: class A { public: void f(char, int) { } private: void f(int, char) { } }; void demo() { A a; a.f('a', 'd'); }- समान नहीं है, लेकिन अधिभार संकल्प समान रूप से काम करता है: सभी उपलब्ध कार्यों पर विचार करें, केवल एक उपयुक्तता पर विचार करने के बाद ही उपयुक्तता पर विचार करें ... दिए गए मामले में, आपको अस्पष्टता भी मिलती है; यदि आप दो चरों को स्वीकार करने के लिए निजी कार्य को बदलते हैं, तो यह निजी होने के बावजूद चुना जाएगा - और आप अगली संकलन त्रुटि में चलते हैं।
एकनकागुआ

14

आप बस अस्पष्टता को मैन्युअल रूप से चुनकर हल कर सकते हैं कि आप किसका उपयोग करना चाहते हैं।

class PlcNetwork : 
  public RouterCallback, 
  public PlcMsgFactoryImplCallback, 
  public MultiCmdQueueCallback {

using NetworkPacket= PlcMsgFactoryImplCallback::NetworkPacket; // <<< add this line
private:
    void sendNetworkPacket(const NetworkPacket &pdu);

}

संकलक केवल आधार वर्गों में परिभाषाओं की तलाश करता है। यदि एक ही प्रकार और या उर्फ ​​दोनों बेस कक्षाओं में मौजूद है, तो यह केवल शिकायत करता है कि यह नहीं जानता कि किसका उपयोग करना है। इससे कोई फर्क नहीं पड़ता कि परिणामी प्रकार समान है या नहीं।

कंपाइलर केवल पहले चरण में नामों की तलाश करता है, पूरी तरह से स्वतंत्र यदि यह नाम एक फ़ंक्शन, प्रकार, उपनाम, विधि या जो कुछ भी है। यदि नाम अस्पष्ट हैं, तो संकलक से कोई और कार्यवाही नहीं की जाती है! यह बस त्रुटि संदेश के साथ शिकायत करता है और बंद हो जाता है। तो बस दिए गए कथन का उपयोग करके अस्पष्टता को हल करें।


शब्द के बारे में कुछ संदेह है। यदि यह परिभाषाओं को देखता है , तो क्या यह प्रकार पर भी विचार नहीं करेगा? क्या यह केवल नामों को ही नहीं देखेगा (और कैसे परिभाषित किया गया है?) मानक के कुछ संदर्भ महान होंगे ...
एकॉनकागुआ

यह आखिरी टिप्पणी है कि क्यों सही ढंग से समझाता है। इस टिप्पणी के साथ अंतिम पैराग्राफ को बदलें और मैं अपवोट हो जाएगा;)
एकॉनगुआ

मैं स्वीकार नहीं कर सकता - मैं प्रश्न लेखक नहीं हूँ ... क्षमा करें, यदि मैं आपकी नसों पर पड़ गया हो। बस उत्तर को बेहतर बनाने की कोशिश कर रहा हूं, जैसा कि मैंने महसूस किया कि इससे पहले क्यूए के मुख्य प्रश्न का उत्तर नहीं दिया था ...
एकॉनगुआ

@Aconcagua: Ubs, मेरी गलती :-) सुधार के लिए धन्यवाद!
क्लॉस

वास्तव में यह काम नहीं करता है क्योंकि दोनों खंडों का उपयोग निजी है। अगर मैं PlcNetwork का उपयोग कर जोड़ता हूं: | NetworkPacket = MultiCmdQueueCallback :: NetworkPacket का उपयोग करना; मुझे एक संकलक त्रुटि मिलती है क्योंकि पिछले का उपयोग करते हुए खंड निजी है। वैसे अगर मैं खंड आधार को सार्वजनिक और अन्य निजी का उपयोग करके एक आधार वर्ग बनाता हूं, तब भी मुझे एक अस्पष्ट त्रुटि मिलती है। मुझे उन तरीकों पर अस्पष्टता त्रुटियां मिलती हैं जो आधार वर्ग में परिभाषित नहीं हैं।
एंड्रयू गोएदरट

8

से डॉक्स :

एक प्रकार का उपनाम अन्य नाम एक परिचय देता है जिसे टाइप-आईडी द्वारा दर्शाए गए प्रकार के पर्याय के रूप में इस्तेमाल किया जा सकता है। यह एक नए प्रकार का परिचय नहीं देता है और यह किसी मौजूदा प्रकार के नाम का अर्थ नहीं बदल सकता है।

हालांकि, वे दो usingखंड एक ही प्रकार का प्रतिनिधित्व करते हैं, संकलक के पास निम्न स्थिति में दो विकल्प हैं:

void sendNetworkPacket(const NetworkPacket &pdu);

इसके बीच चयन कर सकते हैं:

  • MultiCmdQueueCallback::NetworkPacket तथा
  • PlcMsgFactoryImplCallback::NetworkPacket

क्योंकि यह दोनों MultiCmdQueueCallbackऔर PlcMsgFactoryImplCallbackआधार वर्गों से विरासत में मिला है । कंपाइलर के नाम रिज़ॉल्यूशन का एक परिणाम अस्पष्टता त्रुटि है जो आपके पास है। इसे ठीक करने के लिए, आपको संकलक को इस तरह से एक या दूसरे का उपयोग करने के लिए स्पष्ट रूप से निर्देश देने की आवश्यकता है:

void sendNetworkPacket(const MultiCmdQueueCallback::NetworkPacket &pdu);

या

void sendNetworkPacket(const PlcMsgFactoryImplCallback::NetworkPacket &pdu);

सच कहूं तो, मैं संतुष्ट नहीं हूं ... वे दोनों एक ही प्रकार के पर्यायवाची हैं। मैं आसानी से class C { void f(uint32_t); }; void C::f(unsigned int) { }(अन्य मैच उपलब्ध करा सकता हूं )। तो यहाँ एक अंतर क्यों है? वे अभी भी एक ही प्रकार के हैं, आपके उद्धरण द्वारा पुष्टि की गई है (जो कि मुझे समझाने के लिए पर्याप्त नहीं है) ...
एकॉनगुआ

@Aconcagua: आधार प्रकार या उपनाम का उपयोग करने से कभी कोई फर्क नहीं पड़ता। एक उपनाम कभी भी एक नया प्रकार नहीं है। आपके अवलोकन का दो आधार वर्गों में एसएएमई उर्फ ​​देने से आपके द्वारा उत्पन्न अस्पष्टता से कोई लेना-देना नहीं है।
क्लॉस

1
@Aconcagua मुझे लगता है कि आपने उल्लेख किया उदाहरण सवाल से स्थिति के लिए सही समकक्ष नहीं है
NutCracker

ठीक है, चलो थोड़ा बदलाव करें: ए, बी और सी और टाइप डी की कक्षाएं डी का नाम दें, फिर आप भी कर सकते हैं: class C : public A, public B { void f(A::D); }; void C::f(B::D) { }- कम से कम जीसीसी स्वीकार करता है।
एकांकागुआ

प्रश्न लेखक ने शाब्दिक रूप से पूछा कि 'कंपाइलर प्रत्येक का उपयोग क्लॉज को एक अलग प्रकार के रूप में क्यों कर रहा है, हालांकि वे दोनों एक ही अंतर्निहित प्रकार की ओर इशारा करते हैं?' - और मैं यह नहीं देखता कि प्रशस्ति पत्र क्यों स्पष्ट करेगा , इसके बजाय, यह सिर्फ क्यूए की उलझन की पुष्टि करता है ... उत्तर को गलत नहीं कहना चाहता , लेकिन यह मेरी दृष्टि में पर्याप्त रूप से स्पष्ट नहीं करता है। ।
एकॉनगुआ

2

दो त्रुटियां हैं:

  1. निजी प्रकार के उपनामों तक पहुंचना
  2. उपनाम टाइप करने के लिए अस्पष्ट संदर्भ

निजी-निजी

मुझे एक समस्या नहीं दिखती है कि कंपाइलर दूसरी समस्या के बारे में पहले शिकायत करता है क्योंकि ऑर्डर वास्तव में मायने नहीं रखता है - आपको आगे बढ़ने के लिए दोनों मुद्दों को ठीक करना होगा।

सार्वजनिक-सार्वजनिक

आप दोनों की दृश्यता बदलते हैं MultiCmdQueueCallback::NetworkPacketऔर PlcMsgFactoryImplCallback::NetworkPacketया तो सार्वजनिक या संरक्षित, तो दूसरा मुद्दा (अस्पष्टता) के लिए स्पष्ट है - हालांकि वे समान ही अंतर्निहित डेटा प्रकार है उन दो अलग प्रकार का उपनाम है। कुछ लोग सोच सकते हैं कि एक "चतुर" कंपाइलर आपके लिए यह (एक विशिष्ट मामला) हल कर सकता है, लेकिन ध्यान रखें कि कंपाइलर को "सामान्य रूप से सोचने" की ज़रूरत है और केस-विशिष्ट अपवाद बनाने के बजाय वैश्विक नियमों के आधार पर निर्णय लेने की आवश्यकता है। निम्नलिखित मामले की कल्पना करें:

class MultiCmdQueueCallback {
    using NetworkPacketID  = size_t;
    // ...
};


class PlcMsgFactoryImplCallback {
    using NetworkPacketID = uint64_t;
    // ...
};

क्या कंपाइलर को दोनों NetworkPacketIDका समान होना चाहिए ? पक्का - नहीं। क्योंकि 32-बिट सिस्टम पर, size_t32-बिट लंबा है जबकि uint64_tहमेशा 64-बिट है। लेकिन अगर हम चाहते हैं कि कंपाइलर अंतर्निहित डेटा प्रकारों की जांच करें, तो यह 64-बिट सिस्टम पर उन्हें अलग नहीं कर सकता है।

सार्वजनिक निजी

मेरा मानना ​​है कि यह उदाहरण ओपी के उपयोग-मामले में कोई मतलब नहीं रखता है, लेकिन यहाँ हम सामान्य रूप से समस्याओं को हल कर रहे हैं, आइए इस पर विचार करें:

class MultiCmdQueueCallback {
private:
    using NetworkPacket  = Networking::NetworkPacket;
    // ...
};

class PlcMsgFactoryImplCallback {
public:
    using NetworkPacket  = Networking::NetworkPacket;
    // ...
};

मैं इस मामले संकलक व्यवहार करना चाहिए में लगता है PlcNetwork::NetworkPacketके रूप में PlcMsgFactoryImplCallback::NetworkPacket, क्योंकि यह कोई अन्य choises है। क्यों यह अभी भी ऐसा करने से इनकार करता है और अस्पष्टता पर दोष मेरे लिए एक भयावह है।


"क्यों यह अभी भी ऐसा करने से इनकार करता है और अस्पष्टता पर दोष मेरे लिए एक भयावह है।" C ++ में, नाम देखने (दृश्यता) का उपयोग जाँच से पहले होता है। IIRC, मैंने कहीं पढ़ा है कि तर्क यह है कि निजी से सार्वजनिक नाम बदलने से मौजूदा कोड नहीं टूटना चाहिए, लेकिन मुझे पूरी तरह यकीन नहीं है।
एलएफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.