क्या कोई सूचक व्युत्पन्न वस्तुओं की एक सरणी को इंगित कर सकता है?


99

मैं आज नौकरी के लिए इंटरव्यू देने गया और मुझे यह दिलचस्प सवाल दिया गया।

मेमोरी लीक और तथ्य के अलावा कोई वर्चुअल डोर नहीं है, यह कोड क्रैश क्यों होता है?

#include <iostream>

//besides the obvious mem leak, why does this code crash?

class Shape
{
public:
    virtual void draw() const = 0;
};

class Circle : public Shape
{
public:
    virtual void draw() const { }

    int radius;
};

class Rectangle : public Shape
{
public:
    virtual void draw() const { }

    int height;
    int width;
};

int main()
{
    Shape * shapes = new Rectangle[10];
    for (int i = 0; i < 10; ++i)
        shapes[i].draw();
}

1
लापता अर्धविराम के अलावा, आपका मतलब है? (यह एक संकलन-समय की त्रुटि होगी, हालांकि, रनटाइम नहीं)
प्लेटिनम एज़्योर

क्या आप सुनिश्चित हैं कि वे सभी आभासी थे?
योचाई टिम्मर

8
यह होना चाहिए Shape **यह आयतों की एक सरणी की ओर इशारा करता है। तब पहुंच को आकार देना चाहिए था [i] -> ड्रा ();
RedX

2
@ अच्छी किस्मत तब, हमें सूचित रखें :)
सेठ कार्नेगी

2
@AndreyT: कोड अब सही है (और मूल रूप से सही भी था)। ->एक गलती एक संपादक द्वारा बनाया गया था।
आर। मार्टिनो फर्नांडिस

जवाबों:


150

आप ऐसा नहीं कर सकते। आपने एक सरणी आवंटित की है Rectanglesऔर पहली बार में एक पॉइंटर को संग्रहीत किया है shapes। जब आप करते हैं shapes[1]आप dereferencing हैं (shapes + 1)। यह आपको अगले के लिए एक संकेतक नहीं देगा Rectangle, लेकिन Shapeएक अनुमानित सरणी में अगला क्या होगा, इसका संकेत है Shape। बेशक, यह अपरिभाषित व्यवहार है। आपके मामले में, आप भाग्यशाली हैं और एक दुर्घटना हो रही है।

Rectangleइंडेक्सिंग कार्य को सही ढंग से करने के लिए एक पॉइंटर का उपयोग करना ।

int main()
{
   Rectangle * shapes = new Rectangle[10];
   for (int i = 0; i < 10; ++i) shapes[i].draw();
}

यदि आप Shapeसरणी में विभिन्न प्रकार के एस रखना चाहते हैं और उनका उपयोग पॉलीमॉर्फिक रूप से करते हैं, तो आपको शेप में पॉइंटर्स की एक सरणी की आवश्यकता होती है ।


37

जैसा कि मार्टिनो फर्नांडिस ने कहा, अनुक्रमण गलत है। यदि आप आकृतियों के एक सरणी को संग्रहीत करने के बजाय चाहते थे, तो आपको आकृति * की एक सरणी का उपयोग करके ऐसा करना होगा, जैसे:

int main()
{
   Shape ** shapes = new Shape*[10];
   for (int i = 0; i < 10; ++i) shapes[i] = new Rectangle;
   for (int i = 0; i < 10; ++i) shapes[i]->draw();
}

ध्यान दें कि आपको आयत को शुरू करने का एक अतिरिक्त चरण करना होगा, क्योंकि सरणी को आरम्भ करने से केवल बिंदुओं को सेट किया जाता है, न कि वस्तुओं को स्वयं।


13

सूचक को अनुक्रमित करते समय, कंपाइलर सरणी के अंदर स्थित आकार के आधार पर उपयुक्त राशि जोड़ देगा। तो कहते हैं कि आकार (आकार) = 4 (जैसा कि इसका कोई सदस्य चर नहीं है)। लेकिन sizeof (आयत) = 12 (सटीक संख्या गलत होने की संभावना है)।

इसलिए जब आप पहले तत्व के लिए ... 0x0 पर इंडेक्स शुरू करते हैं, तब जब आप 10 वें तत्व को एक्सेस करने की कोशिश करते हैं तो आप एक अमान्य पते या उस स्थान पर जाने का प्रयास करते हैं जो ऑब्जेक्ट की शुरुआत नहीं है।


1
एक गैर c ++ एडेप्ट के रूप में, SizeOf () के उल्लेख से मुझे यह समझने में मदद मिली कि @R क्या है। मार्टिनहो अपने उत्तर में कह रहा था।
मार्जन वेनेमा अगस्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.