2008-11-03 9 views
9

मैं जब मैं इस संकलन के बारे में मैं अप्रयुक्त परम एक्स यह चेतावनी मिलती एक वैकल्पिक आभासी समारोहपैरामीटर खराब अभ्यास के साथ गैर शुद्ध वर्चुअल फ़ंक्शन हैं?

class Base { 
    virtual void OnlyImplementThisSometimes(int x) {} 
}; 

के साथ एक आधार वर्ग की है। क्या कोई अन्य तरीका है जो मुझे वर्चुअल फ़ंक्शन को लागू करना चाहिए था? मैं इसे इस तरह फिर से लिखा है:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) 
    { 
     x = 0; 
    } 
}; 

मैं भी है कि अगर मैं सावधान नहीं हूँ, उपवर्ग मैं गलत समारोह लागू कर सकते हैं और फिर मैं क्योंकि ओवरलोडिंग की सूचना नहीं समस्या है: उदाहरण

class Derived : public Base { 
    void OnlyImplementThisSometimes(int x, int y) { // some code } 
}; 

Derived d; 
Base *b = dynamic_cast<Base *>(&d); 
b->OnlyImplementThisSometimes(x); // calls the method in the base class 

आधार वर्ग विधि क्योंकि मैं एक "int y" परम के साथ व्युत्पन्न समारोह लागू किया लेकिन इस बारे में कोई चेतावनी है बुलाया गया था। क्या सी ++ में ये सामान्य समस्याएं हैं या क्या मैंने वर्चुअल फ़ंक्शंस को गलत समझा है?

उत्तर

22

डिजाइन मुद्दों आप एक अप्रयुक्त चर के बारे में संकलक चेतावनी के आसपास चर नाम को छोड़ते हुए से प्राप्त कर सकते हैं की अनदेखी कर, उदाहरण के लिए:

virtual void OnlyImplementThisSometimes(int) { } 

गलती से जब आभासी समारोह को ओवरराइड करने की कोशिश कर गलत विधि हस्ताक्षर को लागू बस है कुछ ऐसा जो आपको C++ में सावधान रहने की आवश्यकता है। सी # जैसी भाषाएं 'ओवरराइड' कीवर्ड के साथ इसके आसपास आती हैं।

+1

ऐसा करने का दूसरा तरीका (समान प्रभाव) परिवर्तनीय नाम इनलाइन पर टिप्पणी करना है, उदाहरण: int/* x * /। यदि परिवर्तनीय नाम वर्णनात्मक है (जो यह होना चाहिए), यह पाठकों की सहायता करेगा। – Nick

+0

@ निक: मैं दृढ़ता से मजबूत प्रकार की सुरक्षा में विश्वास करता हूं, जहां प्रकार इरादे का वर्णन करता है (और तर्क भ्रम को रोकता है)। यदि आप (ज्यादातर) कोड इस तरह हैं, तो पैरामीटर नाम महत्वपूर्ण नहीं हैं। –

+0

अंतिम अनुच्छेद सी ++ में 'ओवरराइड' कीवर्ड को दर्शाने के लिए संपादित किया जा सकता है। – Rotem

6

इसे बेस क्लास में क्यों परिभाषित करें? यदि बेस क्लास विधि का उपयोग नहीं करेगा, तो बस इसे अपने व्युत्पन्न वर्ग में वर्चुअल विधि के रूप में परिभाषित करें।

या डिफ़ॉल्ट कार्यान्वयन आप एक आभासी समारोह की एक डिफ़ॉल्ट कार्यान्वयन प्रदान करते हैं एक अपवाद

4

फेंक सकता है, यह सब व्युत्पन्न वर्ग है कि उस समारोह को ओवरराइड नहीं करते के लिए एक सही कार्यान्वयन होना चाहिए। यदि आप सही कार्यान्वयन प्रदान नहीं कर सकते हैं, तो मेरी सलाह एक शुद्ध वर्चुअल फ़ंक्शन बनाना होगा और इसे कार्यान्वयन प्रदान करने के लिए व्युत्पन्न कक्षा में छोड़ देना होगा। व्युत्पन्न कक्षाएं जो विधि को कॉल करने की अनुमति नहीं देती हैं, यह सुनिश्चित करने के लिए अपवाद फेंक सकती है कि यह गलती से उपयोग नहीं किया जाता है।

+0

और यदि आप एक सामान्य कार्यान्वयन के बारे में सोच सकते हैं जो सामान्य रूप से * सही है, लेकिन हमेशा नहीं, तो आप शुद्ध वर्चुअल फ़ंक्शन का कार्यान्वयन प्रदान कर सकते हैं, और सामान्य स्थिति में व्युत्पन्न वर्ग बस इसे कॉल करता है। –

2

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

मैं बेस क्लास में दो खाली आभासी कार्यों को लागू करता हूं: इनिट() और क्लीनअप()। सिंगल थ्रेडेड व्युत्पन्न वर्ग उन्हें प्रभावित नहीं करता है, लेकिन मल्टी-थ्रेडेड एक करता है।

मेरे पास फ़ैक्टरी फ़ंक्शन एप्रोप्र्राइट व्युत्पन्न क्लास बनाता है और फिर पॉइंटर लौटाता है। क्लाइंट कोड केवल बेस क्लास प्रकार के बारे में जानता है और यह इनिट() और क्लीनअप() को कॉल करता है। दोनों परिदृश्य सही काम करते हैं।

बेशक, ऐसा करने के तरीके पर अन्य अच्छे सुझाव हो सकते हैं, लेकिन यह मुहावरे मेरे बहुत सारे कोड के लिए अच्छा काम करता है।

+0

मेरा मानना ​​है कि व्युत्पन्न वर्ग में शुद्ध वर्चुअल फ़ंक्शन को ओवरराइड करना और इसे कुछ भी नहीं करना है, बेस क्लास में ऐसा करने और व्युत्पन्न कक्षा में ओवरराइड करने से कोड का उपयोग करने के लिए स्पष्ट और आसान नहीं है। दुरुपयोग की संभावना कम है, क्योंकि कक्षा के उपयोगकर्ता को इसके बारे में सोचना पड़ता है। – foraidt

3

इसके अलावा बस चर नाम को छोड़ते हुए, कई compilers में आप संकलक बता सकते हैं, कि आप जानते हैं कि यह अप्रयुक्त और इस

int func(int x) 
{ 
    (void) x; 
} 
+0

कड़ाई से बोलते हुए, यह संकलक को नहीं बताता है कि यह अप्रयुक्त और SHUTUP है। यह इसका उपयोग करता है। –

2

यह एक बुरा व्यवहार नहीं है ऐसा करके SHUTUP है और यह एक है एक वर्ग के उन हिस्सों को निर्दिष्ट करने के लिए सामान्य मुहावरे जो कार्यान्वित करने के लिए वैकल्पिक हैं।

वर्तमान में मैं इसे उपयोगकर्ता इनपुट सिस्टम के लिए उपयोग कर रहा हूं, क्योंकि उस वर्ग के उपयोगकर्ता के लिए यह हर विधि को लागू करने के लिए कठिन होगा, भले ही वह संभवतः इसका उपयोग नहीं करेगा।

class mouse_listener{ 
public: 
    virtual ~mouse_listener() {} 

    virtual void button_down(mouse_button a_Button) {} 
    virtual void button_up(mouse_button a_Button) {} 
    virtual void scroll_wheel(mouse_scroll a_Scroll) {} 
    virtual void mouse_move_abs(math::point a_Position) {} 
    virtual void mouse_move_rel(math::point a_Position) {} 
}; 
2

Btw, अगर आप अपने आधार वर्ग पता है, वहाँ कभी नहीं गतिशील अप -casts है, यानी आधार के लिए ली गई से करने के लिए कोई ज़रूरत नहीं है।

Base *b = &d; 

बस के रूप में अच्छी तरह से करना होगा, dynamic_cast<> बजाय जब आप नीचे डाली, यानी आधार से प्राप्त करने के लिए इस्तेमाल किया जाना चाहिए:

if((Derived *d = dynamic_cast<Derived *>(b)) != 0) 
{ 
    // use d 
} 

(और नीचे कलाकारों के मामले में निश्चित रूप से, static_cast<> आमतौर पर के रूप में अच्छी तरह से काम करेगा)

+0

मैं कम से कम एक मामले के बारे में सोच सकता हूं जहां गतिशील अपस्ट्स की आवश्यकता होती है: यदि आप टेम्पलेट पैरामीटर से प्राप्त होते हैं और आपको बेस प्रकार के आधार पर विशिष्ट फ़ंक्शंस को कॉल करने की आवश्यकता होती है।मेरे मामले में यह कुछ ऐसा था: अगर (स्थिरता * एफ = गतिशील_कास्ट (यह)) {f-> set_up();} –

+0

ढांचे की स्थापना के तरीके के कारण, मुझे उस बिंदु पर पता नहीं है समय चाहे परीक्षण केस स्थिरता से प्राप्त हो या नहीं: परीक्षण केस स्वयं टेम्पलेट तर्क से निकला है। –

11

हम के रूप में एक मैक्रो _unused को परिभाषित:।

#define _unused(x) ((void)x) 

तो समारोह को परिभाषित के रूप में:

virtual void OnlyImplementThisSometimes(int x) { _unused(x);} 

यह न केवल शिकायत से संकलक रखती है, बल्कि कोड है कि आप एक्स के बारे में भूल नहीं की है बनाए रखने के किसी भी व्यक्ति को यह स्पष्ट करता है - आप जानबूझकर हैं यह अनदेखी ।

+0

यदि आप क्यूटी के साथ प्रोग्रामिंग कर रहे हैं तो आप Q_UNUSED मैक्रो का उपयोग कर सकते हैं जो इस प्रस्तावित समाधान के समान है। –

-2

इस करने का सबसे सरल जवाब नीचे दिखाया गया है:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) { x;} 
}; 

चर जो (उच्चतम स्तर पर वैसे भी कुलपति ++ से) बिल्कुल कुछ भी नहीं सभी चेतावनियों निकाल देंगे करता है के लिए एक साधारण संदर्भ।

+0

सबसे पहले, यह अभी भी जीसीसी में चेतावनी देता है - वाल ("कथन का कोई प्रभाव नहीं है")। दूसरा, यह सबसे आसान जवाब नहीं है - पैरामीटर नाम छोड़ना है। –

-1

इस प्रयास करें:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) = 0; 
}; 

थोड़ा समय के बाद से मुझे लगता है कि जैसे सामान किया है लेकिन मुझे विश्वास है कि है आप कैसे एक आभासी समारोह घोषित हो गया है।

जैसा कि अन्य ने कहा है, वैरिएबल नाम इस तरह की फ़ंक्शन घोषणाओं में वैकल्पिक हैं।

संबंधित मुद्दे