2010-06-11 18 views
6

ग्रीटिंग्स,सी ++ इंटरफेस के साथ एकाधिक वंशानुक्रम?

मैं जावा पृष्ठभूमि से आया हूं और मुझे एकाधिक विरासत में कठिनाई हो रही है।

मेरे पास आईवीव नामक एक इंटरफ़ेस है जिसमें init() विधि है। मैं प्लान व्यूअर नामक एक नई कक्षा प्राप्त करना चाहता हूं जो ऊपर इंटरफ़ेस को कार्यान्वित करता है और एक और वर्ग का विस्तार करता है। (QWidget)।

मेरे कार्यान्वयन है के रूप में:

IViwer.h (केवल हैडर फ़ाइल, कोई सीपीपी फ़ाइल):

#ifndef IVIEWER_H_ 
#define IVIEWER_H_ 

class IViewer 
{ 
public: 
    //IViewer(); 
    ///virtual 
    //~IViewer(); 
    virtual void init()=0; 
}; 

#endif /* IVIEWER_H_ */ 

मेरे व्युत्पन्न वर्ग।

PlaneViewer.h

#ifndef PLANEVIEWER_H 
#define PLANEVIEWER_H 

#include <QtGui/QWidget> 
#include "ui_planeviewer.h" 
#include "IViewer.h" 
class PlaneViewer : public QWidget , public IViewer 
{ 
    Q_OBJECT 

public: 
    PlaneViewer(QWidget *parent = 0); 
    ~PlaneViewer(); 
    void init(); //do I have to define here also ? 

private: 
    Ui::PlaneViewerClass ui; 
}; 

#endif // PLANEVIEWER_H 

PlaneViewer.cpp

#include "planeviewer.h" 

PlaneViewer::PlaneViewer(QWidget *parent) 
    : QWidget(parent) 
{ 
    ui.setupUi(this); 
} 

PlaneViewer::~PlaneViewer() 
{ 

} 

void PlaneViewer::init(){ 

} 

मेरे प्रश्न हैं:

  1. यह आवश्यक PlaneViewer इंटरफ़ेस में विधि init() घोषित करने के लिए है भी है, क्योंकि यह पहले से ही परिभाषित किया गया है मैं n IVIEW?

2.I कोड ऊपर complie नहीं कर सकता, त्रुटि दे:

PlaneViewer] 0x28): के लिए IViewer ' collect2 `typeinfo को अपरिभाषित संदर्भ: ld 1 से बाहर निकलें स्थिति लौटा

मैं है (क्योंकि सभी मैं चाहता हूँ एक इंटरफेस है, न कार्यान्वयन के रूप में) सीपीपी फ़ाइल में IVIEW के लिए कार्यान्वयन के लिए?

+0

क्या मैं आपके डिजाइन के बारे में पूछ सकता हूं? एक ही विरासत पदानुक्रम में आपको QWidget और IViewer को एक साथ बांधने की आवश्यकता क्यों है? आप एकाधिक विरासत के साथ हल करने की क्या समस्या है? मैं पूछता हूं क्योंकि एकाधिक विरासत कुछ दुर्लभ परिस्थितियों में उपयोगी होती है लेकिन अक्सर समस्याएं अलग-अलग तरीके से हल होती हैं। –

+0

मेरे आवेदन में कई प्रकार के दर्शक हैं जो समान डेटा साझा करते हैं। (3 डी वोक्सेल डेटा) .ईजी: 2 डी दर्शक (एक्सवाई प्लेन, वाईजेड प्लेन, जेडएक्स प्लेन) और एक 3 डी दर्शक। और भविष्य में कुछ और दर्शक होने जा रहे हैं। QWiget डेटा का चित्रण और प्रतिपादन का उपयोग करना है। IView सभी प्रकार के दर्शकों के लिए कमांड विधियों और डेटा घोषित करने के लिए एक सार वर्ग/इंटरफ़ेस है। –

उत्तर

3

यह PlaneViewer इंटरफेस भी विधि init() घोषित करने के लिए आवश्यक है, क्योंकि यह पहले से ही IVIEW में परिभाषित किया गया है?

आपको प्लेन व्यूअर में init() घोषित करने की आवश्यकता नहीं है, लेकिन यदि आप प्लेन व्यूअर एक अमूर्त वर्ग नहीं हैं, जिसका अर्थ है कि आप इसे तुरंत चालू नहीं कर सकते हैं।

यदि आप पूछना चाहते हैं कि क्या आपको 'शून्य init();' PlaneViewer के लिए शीर्षलेख फ़ाइल में और .cpp फ़ाइल में। इसका जवाब है हाँ।

मैं कोड ऊपर complie नहीं कर सकता, त्रुटि दे: PlaneViewer] 0x28): लौटे 1 से बाहर निकलें स्थिति

मुझे लगता है कि या तो आप का निर्माण नहीं कर रहे हैं ld: अपरिभाषित के लिए IViewer 'collect2 `typeinfo के संदर्भ में वही कोड या आपका संकलन आदेश गलत है।

मैंने क्यूटी सामग्री को तोड़ दिया और जी ++ के साथ बस अपना कोड बनाने में सक्षम था।

त्रुटि का अर्थ है कि IViewer क्लास लिंकर द्वारा नहीं मिला था।

मुझे यह त्रुटि मिलती है यदि मैं '= 0' भाग को हटा देता हूं जो 'IViewer :: init()' को शुद्ध वर्चुअल फ़ंक्शन बनाता है। यदि आप IViewer में कन्स्ट्रक्टर और/या विनाशक को असम्बद्ध करते हैं तो आप यह त्रुटि भी प्राप्त कर सकते हैं।

क्या मुझे सीपीपी फ़ाइल में IView के लिए कार्यान्वयन करना है?

नहीं सी ++ परवाह नहीं है अगर यह एक .cpp फ़ाइल या एक .h फ़ाइल में है। जावा के विपरीत, सी/सी ++ प्रीप्रोसेसर पहले सभी को शामिल करता है और सभी कोड वाले एक फ़ाइल को उत्पन्न करता है। इसके बाद यह सी/सी ++ कंपाइलर को पास करता है। यदि आप चाहें तो आप वास्तव में एक .cpp शामिल कर सकते हैं। हालांकि एक अच्छा विचार नहीं है।

7

इंटरफ़ेस कक्षाओं के बारे में सोचने का एक अच्छा तरीका यह है कि वे निर्दिष्ट करते हैं कि कक्षाओं को किस प्रकार से लागू किया जाना चाहिए।

यह विधि भी PlaneViewer इंटरफ़ेस में init() घोषित करने के लिए आवश्यक है, क्योंकि यह पहले से ही IVIEW में परिभाषित किया गया है?

त्वरित जवाब है कि हाँ तुम क्योंकि आधार वर्ग विधि शुद्ध आभासी के रूप में घोषित किया जाता है में IViewer में init विधि को लागू करना चाहिए है। इसका मतलब यह है चाहिए कि किसी भी व्युत्पन्न वर्ग है कि विधि का अपना कार्यान्वयन प्रदान के रूप में वहाँ कोई आधार वर्ग पद्धति लागू है।

2।मैं कोड ऊपर complie नहीं कर सकते, देना त्रुटि:

PlaneViewer] 0x28): अपरिभाषित के लिए IViewer ' collect2 `typeinfo के संदर्भ: ld लौटे 1 से बाहर निकलें स्थिति

यह एक छ ++ संकलक त्रुटि है कि इंगित करता है है (जैसा कि ऊपर बताया गया है) कि आपके पास एक आधार से व्युत्पन्न वर्ग है जिसमें शुद्ध वर्चुअल फ़ंक्शन है और व्युत्पन्न वर्ग शुद्ध वर्चुअल विधि, लागू नहीं करता है क्योंकि इसे होना चाहिए।

ओह और यह भी ध्यान दिया जाना चाहिए कि आपको एकाधिक विरासत के साथ कोई समस्या नहीं है, समस्या तब भी मौजूद होगी जब केवल IViewer और PlaneViewer शामिल थे।

2

हां, आपको उप-वर्ग में virtual void init() फिर से घोषित करने और इसे कार्यान्वित करने की आवश्यकता है, क्योंकि IViewer फ़ंक्शन को शुद्ध आभासी घोषित करता है।

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

अतिरिक्त नोट के रूप में, you should provide virtual destructors with empty body for your interfaces

4

हां, आपको अपने PlaneViewer में init घोषित करना होगा। यदि आपने नहीं किया, तो initPlaneViewer और PlaneViewer में मौजूद नहीं होगा, अभी भी सार माना जाएगा (क्योंकि init का कोई कार्यान्वयन नहीं है)।

आपको IViewer में अपने (वर्चुअल) विनाशक के लिए खाली निकायों को परिभाषित करने की आवश्यकता है। सी ++ में "इंटरफेस" वास्तव में इंटरफेस नहीं हैं, यह केवल सम्मेलन द्वारा है कि आप सभी शुद्ध वर्चुअल विधियों और कोई फ़ील्ड वाले वर्ग नहीं बनाते हैं: हालांकि, वे अभी भी कंपाइलर के दृष्टिकोण से "नियमित" कक्षाएं हैं, इसलिए आप अभी भी विनाशक के कार्यान्वयन की आवश्यकता है।

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

    virtual void init() = 0; 
}; 
3

टाइपइन्फो मुद्दा IViewer क्लास के लिए विनाशक के कार्यान्वयन के कारण नहीं होता है। आम तौर पर कंपाइलर्स आभासी विनाशक के साथ आंतरिक डेटा संरचनाओं (उदाहरण के लिए "टाइपइन्फो") उत्पन्न करेंगे।

आप संकलन और स्थापित करता है, एक फ़ाइल को लिंक करना होगा:

#include "iviewer.h" 

IViewer::~IViewer() { } 

यह इसलिए है क्योंकि इस RTTI जानकारी का उपयोग करने संकलक एक संकलन इकाई देता है एक आभासी नाशक के लिए अच्छा अभ्यास है, और यह भी हटाने की अनुमति देता है बेस क्लास पॉइंटर पर कॉल करते समय ऑपरेटर सही ढंग से काम करने के लिए।

अन्य ने init() विधि पर सवाल का जवाब दिया है, लेकिन संक्षेप में: यदि आप इसे प्लेन व्यूअर में लागू करने जा रहे हैं, तो आपको इसे घोषित करने की आवश्यकता है।

2

मैं दोनों भाषाओं में महत्वपूर्ण कार्य किया है और एक कुकी कटर पैटर्न आप आमतौर पर एक ग में एक जावा इंटरफ़ेस चालू करने के लिए अनुसरण कर सकते हैं ++ इंटरफेस है:

// जावा इंटरफ़ेस

interface Numeric { 
    public int  toInteger(); 
    public double toDouble(); 
}; 
से शुरू करें

सी ++ जावा को पूर्ववत करता है और शुद्ध आभासी कक्षाओं के लिए विशेष "इंटरफ़ेस" कीवर्ड को परिभाषित करने से परेशान नहीं करता है। तो अगर आप को प्रभावी ढंग से है कि जावा संकलक स्वचालित रूप से करता है कुछ काम करना है:

// बराबर सी ++ वर्ग

class Numeric { 
private: 
    Numeric(const Numeric&); 
    Numeric& operator=(const Numeric&); 
public: 
    Numeric() {} 
    virtual ~Numeric() {} 

    virtual int toInteger() = 0; 
    virtual double toDouble() = 0; 
}; 

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

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