मेरे पास एक वर्ग है, Table, जिसमें एक सदस्य height है। height का मान या तो एक इंट होना चाहिए या उस ऑब्जेक्ट की ओर इशारा करना चाहिए जिसमें अतिरिक्त डेटा हो।

यहां उद्देश्य यह है कि उपयोगकर्ता या तो एक सीधा मान इनपुट कर सकता है, या एक पूर्वनिर्धारित मान (इसकी आईडी द्वारा पहचाना गया) चुन सकता है जिसे कई Table ऑब्जेक्ट द्वारा साझा किया जा सकता है।

यह एक तरीका है जिससे मुझे लगता है कि मैं इस कार्यक्षमता को प्राप्त कर सकता हूं।

1) एक बेस क्लास Height बनाएं।

2) दो उपवर्ग हैं Height और PredefinedHeight

Height में केवल ऊंचाई वाला एक पूर्णांक होगा (गेट्टर और सेटर के साथ), और PredefinedHeight में अतिरिक्त डेटा होगा:

class PredefinedHeight : public Height
{ 

    public: 

    void setHeight(int height);
    void setId(int id);
    void setName(std::string name);

    int getHeight();
    int getId();
    std::string getName();

   private:

   int height;
   int id;
   std::string name;

}; 

Table के अंदर, ऊंचाई वाला सदस्य Height प्रकार का होगा।

मुझे लगता है कि यह व्यवहार में काम करेगा, हालांकि मेरे पास एक और मुद्दा है। जब इस डेटा को प्रदर्शित करने की बात आती है, यदि height एक सीधा मान है (प्रकार Height), तो इसे केवल int height प्रदर्शित करना चाहिए। यदि यह एक PredefinedHeight है, तो इसे id और name भी प्रदर्शित करना चाहिए। मेरे पास दोनों वर्गों में वर्चुअल विधि std::string getData() हो सकती है जो आवश्यक डेटा लौटाती है लेकिन स्ट्रिंग को प्रारूपित करने के लिए कक्षाओं पर भरोसा करना गन्दा लगता है।

वैकल्पिक रूप से मैं एक गतिशील कलाकार का उपयोग कर सकता था, लेकिन चिंता करें कि इस मामले में यह खराब अभ्यास हो सकता है।

क्या किसी के पास बेहतर सुझाव है?

1
19172281 25 मई 2020, 02:41

2 जवाब

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

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

संदर्भ एक स्ट्रिंग संग्रहीत नहीं करना चाहिए। मुझे यकीन है कि नाम आपके द्वारा संदर्भित किसी भी चीज़ की एक संपत्ति है, इसलिए इसे हर जगह कॉपी करना प्रतिकूल है। फिर, Height वस्तु इतनी छोटी है कि आप इसे ढेर पर आवंटित नहीं करना चाहते हैं - इसे मूल्य द्वारा संग्रहीत किया जाना चाहिए। वस्तु अपने आप में एक मूल्य है, लेकिन इसमें वास्तविक मूल्य, या इसका संदर्भ हो सकता है।

इस प्रकार, इसके बारे में जाने के कई तरीकों में से एक ऐसा कुछ है:

struct Height { int value; };
struct HeightRef { Height &value; }; // actually bigger than Height on 64 bit systems!

using HeightOrHeightRef = ...;
class MyClass {
  std::string objectName;
  HeightOrHeightRef height;
  ...
};

अब: यह क्या है HeightOrHeightRef? यह या तो std::variant होना चाहिए (यदि आपका प्रोजेक्ट C++17 की अनुमति देता है), या https://github .com/mapbox/variant, या boost::variant। इस तरह:

using HeightOrHeightRef = std::variant<Height, HeightRef>;

यह ठीक है और बांका है, लेकिन आप लगभग तुरंत ही जीवन भर के प्रबंधन के मुद्दों में भाग लेते हैं: HeightRef को पूरी तरह से आवश्यकता होती है कि जिस ऊंचाई वस्तु का संदर्भ दिया जाता है वह अंतिम HeightRef के चले जाने तक उपलब्ध हो।

आदर्श रूप से, आपको समझना चाहिए कि वस्तु का जीवनकाल और स्वामित्व मॉडल आपका डेटा प्रतिनिधित्व क्या है - और इसके उपयोग - मांग, और इसके आधार पर आगे बढ़ें।

बेहतर विचारों के अभाव में, आप संदर्भ को किसी साझा सूचक के स्वामित्व वाली वस्तु का कमजोर संदर्भ बना सकते हैं:

struct Height { int value; };
class HeightRef 
{
 std::weak_ptr<MyClass> m_valueHolder;
public:
 HeightRef(std::weak_ptr<MyClass> withHeight) : m_valueHolder(withHeight) {}
 std::optional<Height> height() const;
};

using HeightOrHeightRef = std::variant<Height, HeightRef>;

class MyClass : public std::enable_shared_from_this<MyClass>
{
  HeightOrHeightRef m_height;
public:
  HeightRef heightRef() const { return {weak_from_this()}; }
  Height height() const { return m_height; }
};

फिर, ऊंचाई प्राप्त करने के लिए, कमजोर सूचक को एक साझा सूचक में परिवर्तित करके लॉक किया जाना चाहिए, और फिर स्रोत वर्ग से ऊंचाई पढ़ी जाती है - या स्रोत वर्ग अब मौजूद नहीं होने पर कोई मान वापस नहीं किया जाता है:

std::optional<Height> HeightRef::height() const
{
  auto myObject = m_valueHolder.lock();
  if (myObject) return myObject->height();
  return {}; // no value
}

कोड जो ऊंचाई की अपेक्षा करता है, उसे अनुपस्थित होने पर संभालने की आवश्यकता होती है यदि आपके डेटा मॉडल में ऑब्जेक्ट आजीवन नियम ऐसी घटना की अनुमति देते हैं। आपने निश्चित रूप से पर्याप्त नहीं कहा कि आपको क्यों लगता है कि आपको संदर्भ की आवश्यकता है - अक्सर ऐसे विचार अधिक इंजीनियर होते हैं।

यदि कई स्वतंत्र वर्ग हैं जो height() मान प्रदान करते हैं, तो आप किसी दिए गए वर्ग में height() मान तक पहुंचने के लिए वर्चुअल विधि का उपयोग कर सकते हैं, या आप संकलन समय पर ऐसा करने के लिए फ़ंक्शन उत्पन्न कर सकते हैं, और इसके सूचक को संदर्भ में संग्रहीत करें:

class HeightRef 
{
  using Accessor = Height (*)(const MyBaseClass &);
  std::weak_ptr<MyBaseClass> m_valueHolder; // a base class but needs no virtual methods
  Accessor m_valueAccessor;
public:
  template <class WithHeight>
  HeightRef(std::weak_ptr<WithHeight> withHeight) :
    m_valueHolder(withHeight),
    m_valueAccessor([](const MyBaseClass&withHeight) -> Height {
      return static_cast<WithHeight&>(withHeight).height();
    })
  {}
  std::optional<Height> height() const;
};

std::optional<Height> HeightRef::height() const
{
  auto myObject = m_valueHolder.lock();
  if (myObject && m_valueAccessor) 
    return m_valueAccessor(*myObject);
  return {}; // no value
}

std::optional बूलियन संदर्भों में एक पॉइंटर की तरह व्यवहार करता है: यदि इसका कोई मूल्य नहीं है, तो यह "गलत" होगा। इसलिए, यह जांचने के लिए कि क्या HeightRef वैध है, if (ref) का उपयोग करें:

if (heightRef)
{
  Height height = *heightRef;
  ... (use the height for something)
}
1
Reinstate Monica 25 मई 2020, 03:47

ऊंचाई का मान या तो एक इंट होना चाहिए या उस संरचना की ओर इशारा करना चाहिए जिसमें अतिरिक्त डेटा हो

इसे सम प्रकार उर्फ ​​एक टैग की गई यूनियन कहा जाता है

C++ इसके लिए एक मानक टेम्पलेट है: std::variant। आप शायद अंदर कुछ स्मार्ट पॉइंटर का उपयोग करना चाहते हैं।

यदि आप उस हेडर का उपयोग नहीं कर सकते हैं, तो अपने class के अंदर कुछ union का उपयोग करके इसे फिर से लागू करें (किसी अन्य सदस्य के साथ उस संघ में भेदभाव करना, जो यह), लेकिन को फ़ॉलो करना न भूलें पांच का नियम

मैं सी ++ के बारे में और पढ़ने की सलाह देता हूं। सबसे पहले, प्रोग्रामिंग -- C++ के प्रयोग के सिद्धांत और अभ्यास और बाद में C++ 11 मानक n3337

0
Basile Starynkevitch 25 मई 2020, 09:09