मेरे C ++ कोड में कक्षा की अन्योन्याश्रयता कैसे हल करें?


10

मेरे C ++ प्रोजेक्ट में, मेरे पास दो कक्षाएं हैं, Particleऔर Contact। में Particleवर्ग, मैं एक सदस्य चर है std::vector<Contact> contactsजो एक के सभी संपर्कों को शामिल Particleवस्तु, और इसी सदस्य कार्यों getContacts()और addContact(Contact cont)। इस प्रकार, "Particle.h" में, मैं "Contact.h" शामिल करता हूं।

में Contactवर्ग, मैं कोड के लिए निर्माता को जोड़ना चाहते हैं Contactकि कॉल करेंगे Particle::addContact(Contact cont)तो यह है कि, contactsदोनों के लिए अद्यतन किया जाता है Particleजिन वस्तुओं पर के बीच Contactवस्तु जोड़ा जा रहा है। इस प्रकार, मुझे "Contact.cpp" में "पार्टिकल.एच" को शामिल करना होगा।

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


इन वर्गों को एक Networkवर्ग द्वारा एक साथ बांधा जाएगा जिसमें एन कण ( std::vector<Particle> particles) और एनसी संपर्क ( std::vector<Contact> contacts) होंगे। लेकिन मैं इस तरह के कार्य करने में सक्षम होना चाहता था particles[0].getContacts()- क्या Particleइस मामले में कक्षा में इस तरह के कार्य करना ठीक है , या इस उद्देश्य के लिए C ++ में एक बेहतर संघ "संरचना" है (दो संबंधित वर्गों का एक अन्य वर्ग में उपयोग किया जा रहा है) ।


मुझे यहां एक दृष्टिकोण बदलाव की आवश्यकता हो सकती है कि मैं इसे कैसे संपर्क कर रहा हूं। चूँकि दो वर्ग एक Networkक्लास ऑब्जेक्ट से जुड़े होते हैं , क्या यह विशिष्ट कोड / क्लास ऑर्गनाइजेशन है जिससे कनेक्टिविटी की जानकारी पूरी तरह से Networkऑब्जेक्ट द्वारा नियंत्रित होती है (जिसमें एक कण ऑब्जेक्ट को उसके संपर्कों के बारे में पता नहीं होना चाहिए और, परिणामस्वरूप, इसका getContacts()सदस्य नहीं होना चाहिए। समारोह)। फिर, यह जानने के लिए कि किसी विशिष्ट कण में क्या संपर्क है, मुझे Networkऑब्जेक्ट के माध्यम से वह जानकारी प्राप्त करने की आवश्यकता होगी (उदाहरण के लिए, उपयोग करना network.getContacts(Particle particle))।

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


4
यहाँ cppcon 2017 से एक बात सामने आई है - The Three Layers of Headers: youtu.be/su9ittf-ozk
Robert Andrzejuk

3
ऐसे प्रश्न जिनमें "सर्वश्रेष्ठ," "बेहतर" और "स्वीकार्य" जैसे शब्द शामिल हैं, जब तक आप मूल्यांकन के अपने विशिष्ट मानदंडों को नहीं बता सकते।
रॉबर्ट हार्वे

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

@RobertHarvey मैंने अपने अंतिम खंड में "बेहतर" और "बुरा" हटा दिया। मुझे लगता है कि जब आप एक Networkक्लास ऑब्जेक्ट होता है जिसमें Particleऑब्जेक्ट्स और Contactऑब्जेक्ट होते हैं, तो मैं ठेठ (शायद इष्ट / प्रोत्साहित) दृष्टिकोण के लिए पूछ रहा हूं । उस आधार ज्ञान के साथ, फिर मैं यह आकलन करने की कोशिश कर सकता हूं कि यह मेरी विशिष्ट आवश्यकताओं के साथ फिट है या नहीं, जो अभी भी पता लगाया जा रहा है / विकसित किया गया है क्योंकि मैं परियोजना में साथ जाता हूं।
AnInquiringMind

@RobertHarvey मुझे लगता है कि मैं सी + + परियोजनाओं को पूरी तरह से खरोंच से लिखने के लिए नया हूं कि मैं "ठेठ" और "लोकप्रिय" सीखने के साथ ठीक हूं। उम्मीद है कि मैं कुछ बिंदु पर पर्याप्त अंतर्दृष्टि प्राप्त कर पाऊंगा ताकि यह महसूस किया जा सके कि वास्तव में एक और कार्यान्वयन क्यों बेहतर है, लेकिन अभी के लिए, मैं सिर्फ यह सुनिश्चित करना चाहता हूं कि मैं पूरी तरह से हड्डी-रहित तरीके से इस से संपर्क नहीं कर रहा हूं!
इंकवायरिंगमाइंड

जवाबों:


17

आपके प्रश्न के दो भाग हैं।

पहला भाग C ++ हेडर फ़ाइलों और स्रोत फ़ाइलों का संगठन है। इसे आगे की घोषणा और वर्ग घोषणा के पृथक्करण (हेडर फ़ाइल में डालकर) और विधि निकाय (उन्हें स्रोत फ़ाइल में डालकर) का उपयोग करके हल किया जाता है । इसके अलावा, कुछ मामलों में व्यक्ति कठिन मामलों को हल करने के लिए पिंपल मुहावरे ("लागू करने के लिए सूचक") लागू कर सकता है । सर्वोत्तम प्रथाओं के अनुसार साझा-स्वामित्व पॉइंटर्स ( shared_ptr), एकल-स्वामित्व पॉइंटर्स ( unique_ptr), और गैर-स्वामित्व वाले पॉइंटर्स (रॉ पॉइंटर, यानी "तारांकन") का उपयोग करें।

दूसरा भाग है कि वस्तुओं को कैसे चित्रित किया जाए जो एक ग्राफ के रूप में अंतर-संबंधित हैं । सामान्य रेखांकन जो डीएजी नहीं हैं (निर्देशित एसाइक्लिक ग्राफ) में वृक्ष के समान स्वामित्व व्यक्त करने का स्वाभाविक तरीका नहीं है। इसके बजाय, नोड्स और कनेक्शन सभी मेटाडेटा हैं जो एकल ग्राफ़ ऑब्जेक्ट से संबंधित हैं। इस मामले में, नोड-कनेक्शन संबंध को एकत्रीकरण के रूप में मॉडल करना संभव नहीं है। नोड्स "स्वयं" कनेक्शन नहीं करते हैं; कनेक्शन "स्वयं" नोड नहीं हैं। इसके बजाय, वे संघ हैं, और दोनों नोड्स और कनेक्शन ग्राफ के "स्वामित्व" हैं। ग्राफ क्वेरी और हेरफेर विधि प्रदान करता है जो नोड्स और कनेक्शन पर काम करते हैं।


जवाब देने के लिए धन्यवाद! मेरे पास वास्तव में एक नेटवर्क वर्ग है जिसमें N कण और Nc संपर्क होंगे। लेकिन मैं इस तरह के कार्य करने में सक्षम होना चाहता था particles[0].getContacts()- क्या आप अपने अंतिम पैराग्राफ में सुझाव दे रहे हैं कि मुझे Particleकक्षा में ऐसे कार्य नहीं करने चाहिए , या वर्तमान संरचना ठीक है क्योंकि वे स्वाभाविक रूप से संबंधित / संबंधित हैं Network? क्या इस मामले में C ++ में एक बेहतर एसोसिएशन "संरचना" है?
AnInquiringMind

1
आमतौर पर यह कि नेटवर्क वस्तुओं के बीच संबंधों के बारे में जानने के लिए जिम्मेदार है। यदि आप एक आसन्न सूची का उपयोग करते हैं, उदाहरण के लिए, कण इसके संपर्कों के सूचकांकों के साथ network.particle[p]संगत होगा network.contacts[p]। अन्यथा, नेटवर्क और कण किसी तरह दोनों एक ही जानकारी को ट्रैक कर रहे हैं।
बेकार

@ हाँ, यह है कि जहाँ मैं कैसे आगे बढ़ने के लिए अनिश्चित हूँ। तो आप कह रहे हैं कि Particleवस्तु को उसके संपर्कों के बारे में पता नहीं होना चाहिए (इसलिए मेरे पास getContacts()सदस्य कार्य नहीं होना चाहिए ), और यह कि जानकारी केवल Networkवस्तु के भीतर से ही आनी चाहिए ? क्या किसी Particleवस्तु के लिए C ++ कक्षा का डिज़ाइन खराब होगा , उस ज्ञान (अर्थात, उस जानकारी तक पहुंचने के कई तरीके हैं - या तो Networkऑब्जेक्ट या ऑब्जेक्ट के माध्यम से Particle, जो भी अधिक सुविधाजनक लगता है)? उत्तरार्द्ध मुझे अधिक समझ में आता है, लेकिन शायद मुझे इस पर अपना दृष्टिकोण बदलने की आवश्यकता है।
इनक्वायरिंगमाइंड

1
@PhysicsCodingEnthyer: एस या एस के Particleबारे में कुछ भी जानने के साथ समस्या यह है कि यह आपको उस रिश्ते का प्रतिनिधित्व करने के एक विशिष्ट तरीके से जोड़ता है । तीनों वर्गों को सहमत होना पड़ सकता है। यदि इसके बजाय केवल वही है जो जानता है या परवाह करता है, तो यह केवल एक वर्ग है जिसे बदलने की आवश्यकता है यदि आप एक और प्रतिनिधित्व तय करते हैं तो बेहतर है। ContactNetworkNetwork
cHao

@cHao ठीक है, यह समझ में आता है। तो Particleऔर Contactपूरी तरह से अलग होना चाहिए, और उनके बीच का संबंध Networkवस्तु द्वारा परिभाषित किया गया है। बस पूरी तरह से सुनिश्चित हो, यह (शायद) क्या @rwong का मतलब है जब उसने लिखा था, "दोनों नोड्स और कनेक्शन ग्राफ के" स्वामित्व "हैं। ग्राफ क्वेरी और हेरफेर के तरीके प्रदान करता है जो नोड्स और कनेक्शन पर काम करते हैं।" , सही?
इंकमिरिंगमाइंड

5

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

तो पहली बात जो मुझे लगता है कि संदिग्ध है Particleएक सदस्य चर क्यों है std::vector<Contact>? यह एक std::vector<Contact*>या std::vector<std::shared_ptr<Contact> >इसके बजाय होना चाहिए । addContactउसके बाद अलग हस्ताक्षर होने चाहिए जैसे कि addContact(Contact *cont)या addContact(std::shared_ptr<Contact> cont)इसके बजाय।

इससे "Particle.h" में "Contact.h" को शामिल करना अनावश्यक हो गया है, "Particle.h" में आगे की घोषणा class Contact, और "Particle.cpp" में "Contact.h" का एक संयोजन पर्याप्त होगा।

फिर कंस्ट्रक्टर के बारे में सवाल। आप जैसा कुछ चाहते हैं

 Contact(Particle &p1, Particle &p2)
 {
      p1.addContact(this);
      p2.addContact(this);
 }

सही? यह डिज़ाइन ठीक है, जब तक कि आपका कार्यक्रम हमेशा उस समय संबंधित कणों को जानता है जब संपर्क वस्तु का निर्माण करना होता है।

ध्यान दें, यदि आप std::vector<Contact*>मार्ग जाते हैं, तो आपको Contactवस्तुओं के जीवनकाल और स्वामित्व के बारे में कुछ विचार निवेश करने होंगे । कोई भी कण इसके संपर्कों का "मालिक" नहीं है, एक संपर्क को केवल तभी हटाया जाएगा जब दोनों संबंधित Particleवस्तुएं नष्ट हो जाएं। std::shared_ptr<Contact>इसके बजाय उपयोग करने से आपके लिए यह समस्या अपने आप हल हो जाएगी। या आप "आसपास के संदर्भ" ऑब्जेक्ट को कणों और संपर्कों (जैसे @rwong द्वारा सुझाए गए) का स्वामित्व लेते हैं, और उनके जीवनकाल का प्रबंधन करते हैं।


मुझे addContact(const std::shared_ptr<Contact> &cont)ओवर का लाभ दिखाई नहीं दे रहा है addContact(std::shared_ptr<Contact> cont)?
कैलिथ

@ कैलेथ: इस पर यहां चर्चा की गई: stackoverflow.com/questions/3310737/… - "कॉन्स्ट" वास्तव में यहां महत्वपूर्ण नहीं है, लेकिन संदर्भ द्वारा वस्तुओं को पास करना (और मूल्य द्वारा स्केलर) C ++ में मानक मुहावरा है।
डॉक ब्राउन

2
उन जवाबों में से कई एक पूर्व moveप्रतिमान से लगते हैं
Caleth

@ कैलेथ: ठीक है, सभी नाइटपिकर्स को खुश रखने के लिए, मैंने अपने उत्तर के इस महत्वहीन हिस्से को बदल दिया।
डॉक ब्राउन

1
@PhysicsCodingEnthusiast: नहीं, यह करने के बारे में सबसे महत्वपूर्ण है particle1.getContacts()और particle2.getContacts()एक ही पहुंचाने Contactवस्तु के बीच शारीरिक संपर्क का प्रतिनिधित्व करने particle1और particle2, और नहीं दो अलग-अलग वस्तुओं। बेशक, कोई इस तरह से सिस्टम को डिजाइन करने की कोशिश कर सकता है अगर यह एक Contactही भौतिक संपर्क का प्रतिनिधित्व करने वाले एक ही समय में दो ऑब्जेक्ट उपलब्ध न हो। यह Contactअपरिवर्तनीय बनाने के लिए शामिल होगा , लेकिन क्या आप सुनिश्चित हैं कि यह वही है जो आप चाहते हैं?
डॉक्टर ब्राउन

0

हां, आप जो वर्णन करते हैं, वह यह सुनिश्चित करने का एक बहुत स्वीकार्य तरीका है कि हर Contactउदाहरण ए के संपर्कों की सूची में है Particle


जवाब देने के लिए धन्यवाद। मैंने कुछ सुझाव पढ़ा था कि अन्योन्याश्रित वर्गों की एक जोड़ी होने से बचा जाना है (उदाहरण के लिए, एमएस जोशी द्वारा "C ++ डिजाइन पैटर्न और डेरिवेटिव्स प्राइसिंग"), लेकिन जाहिर है कि यह सही नहीं है? जिज्ञासा से बाहर, क्या अंतर-निर्भरता की आवश्यकता के बिना इस स्वचालित अद्यतन को लागू करने का एक और तरीका है?
InquiringMind

4
@PhysicsCodingEnthyer: अन्योन्याश्रित वर्ग होने से सभी प्रकार की कठिनाइयां पैदा होती हैं और आपको उनसे बचने की कोशिश करनी चाहिए। लेकिन कभी-कभी, दो वर्ग एक-दूसरे से इतने निकट से संबंधित होते हैं कि उनके बीच अन्योन्याश्रयता को हटाने से अन्योन्याश्रय की तुलना में अधिक समस्याएं होती हैं।
बार्ट वैन इनगेन शेनॉउ

0

आपने जो किया है वह सही है।

एक और तरीका ... यदि उद्देश्य यह सुनिश्चित करना है कि प्रत्येक Contactसूची में है, तो आप यह कर सकते हैं:

  • Contact(निजी निर्माणकर्ता) का ब्लॉक निर्माण ,
  • आगे घोषित Particleवर्ग,
  • बनाने Particleके एक दोस्त वर्ग Contact,
  • Particleएक कारखाना विधि बनाने में जो एक बनाता हैContact

तो फिर तुम शामिल करने के लिए की जरूरत नहीं है particle.hमेंcontact


जवाब देने के लिए धन्यवाद! जो इसे लागू करने का एक उपयोगी तरीका लगता है। बस सोचकर, Networkकक्षा के संबंध में प्रारंभिक प्रश्न को संपादित करने के साथ , क्या यह सुझाव दिया संरचना को बदलता है, या क्या यह अभी भी वैसा ही होगा?
InquiringMind

आपके द्वारा अपना प्रश्न अपडेट करने के बाद, यह गुंजाइश बदल रहा है। ... अब आप अपने आवेदन की वास्तुकला के बारे में पूछ रहे हैं, जब पहले यह एक तकनीकी मुद्दे के बारे में था।
रॉबर्ट एंड्रेजजुक

0

एक और विकल्प जिस पर आप विचार कर सकते हैं, वह है कॉन्टेक्ट कंस्ट्रक्टर को बनाना जो एक पार्टिकल रेफरेंस को स्वीकार करता है। यह किसी भी कंटेनर को लागू करने के लिए एक संपर्क को जोड़ने की अनुमति देगा addContact(Contact)

template<class Container>
Contact(/*parameters*/, Container& container)
{
  container.addContact(*this);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.