एक ही सी/सी ++ आवेदन के रूपों को बनाने का सबसे अच्छा तरीका क्या है

मेरे पास तीन करीबी संबंधित अनुप्रयोग हैं जो एक ही स्रोत कोड से बने हैं - मान लें कि APP_A, APP_B, और APP_C। APP_C APP_B का एक सुपरसेट है जो बदले में APP_A का सुपरसेट है।

अब तक मैं एक प्रीप्रोसेसर परिभाषित कर रहा हूं ताकि एप्लिकेशन को बनाया जा सके, जिसने इस तरह काम किया है।

// File: app_defines.h
#define APP_A 0
#define APP_B 1
#define APP_C 2

मेरे आईडीई बिल्ड विकल्प तब निर्दिष्ट करें (उदाहरण के लिए)

#define APPLICATION APP_B

... और स्रोत कोड में, मेरे पास चीजें होंगी

#include "app_defines.h"

#if APPLICATION >= APP_B
// extra features for APPB and APP_C
#endif

हालांकि, मैंने आज सुबह पैर में खुद को गोली मार दी और एक फ़ाइल से #include "app_defines.h" को लाइन को छोड़कर बहुत समय तक बर्बाद कर दिया। सब कुछ ठीक संकलित, लेकिन एप्लिकेशन स्टार्टअप पर एवीएस के साथ दुर्घटनाग्रस्त हो गया।

मैं जानना चाहता हूं कि इसे संभालने का एक बेहतर तरीका क्या होगा। इससे पहले, यह आम तौर पर कुछ बार में से एक होगा जब मुझे लगता है कि # डिफाईन का उपयोग किया जा सकता है (सी ++ में, वैसे भी), लेकिन मैं अभी भी बुरी तरह से गुम हो गया और संकलक ने मेरी रक्षा नहीं की।

0

11 उत्तर

Check out Alexandrescu's Modern C++ Design. He presents the policy based development using templates. Basically, this approach is an extension of the strategy pattern with the difference being that all choices are made at compile time. I think of Alexandrescu's approach as being similar to using the PIMPL idiom, but implementing with templates.

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

0
जोड़ा

You may also find some help in this similar one I asked: Writing cross-platform apps in C

0
जोड़ा

आपको हमेशा उन अनुप्रयोगों में विरासत संबंधों को मजबूर नहीं करना पड़ता है जो एक सामान्य कोड बेस साझा करते हैं। वास्तव में।

एक पुरानी यूनिक्स चाल है जहां आप argv [0], यानी, एप्लिकेशन नाम के आधार पर आपके आवेदन के व्यवहार को तैयार करते हैं। अगर मुझे सही याद आती है (और जब मैंने इसे देखा तो 20 साल हो गए हैं), आरएसएस और रूलॉगिन एक ही कमांड थे। आप बस argv [0] के मान के आधार पर रनटाइम कॉन्फ़िगरेशन करते हैं।

यदि आप बिल्ड कॉन्फ़िगरेशन के साथ चिपकना चाहते हैं, तो यह आमतौर पर उपयोग किया जाने वाला पैटर्न है। आपकी बिल्ड सिस्टम/मेकफ़ाइल कमांड पर एक प्रतीक को परिभाषित करती है जैसे APP_CONFIG एक गैर-शून्य मान होने के बाद आपके पास कॉन्फ़िगरेशन नट्स और बोल्ट के साथ एक सामान्य फ़ाइल शामिल है।

#define APP_A 1
#define APP_B 2

#ifndef APP_CONFIG
#error "APP_CONFIG needs to be set
#endif

#if APP_CONFIG == APP_A
#define APP_CONFIG_DEFINED
// other defines
#endif

#if APP_CONFIG == APP_B
#define APP_CONFIG_DEFINED
// other defines
#endif

#ifndef APP_CONFIG_DEFINED
#error "Undefined configuration"
#endif

यह पैटर्न लागू करता है कि कॉन्फ़िगरेशन कमांड लाइन परिभाषित है और मान्य है।

0
जोड़ा
यह थोड़ा बेहतर है लेकिन मेरी समस्या नहीं पकड़ी होगी। मैंने APP_CONFIG परिभाषित किया था, लेकिन ऊपर दिखाए गए "सामान्य शामिल फ़ाइल" को शामिल करना भूल गया था।
जोड़ा लेखक Roddy, स्रोत

What you are trying to do seems very similar to "Product lines". Carnigie Melon University has an excellent page on the pattern here: http://www.sei.cmu.edu/productlines/

यह मूल रूप से विभिन्न क्षमताओं के साथ सॉफ्टवेयर के एक टुकड़े के विभिन्न संस्करणों का निर्माण करने का एक तरीका है। यदि आप क्विकन होम/प्रो/बिजनेस जैसे कुछ कल्पना करते हैं तो आप ट्रैक पर हैं।

हालांकि यह वही नहीं हो सकता है जो आप कोशिश कर रहे हैं, तकनीक उपयोगी होनी चाहिए।

0
जोड़ा
> क्विकन होम/प्रो/बिजनेस - यह बिल्कुल ठीक है।
जोड़ा लेखक Roddy, स्रोत

हो सकता है कि आप उन टूल्स पर नज़र डालें जो उत्पाद लाइनों के विकास का समर्थन करते हैं और एक संरचित तरीके से स्पष्ट संस्करण प्रबंधन को बढ़ावा देते हैं।

इन उपकरणों में से एक शुद्ध :: वेरिएंट शुद्ध-प्रणाली है जो सुविधा के माध्यम से परिवर्तनशीलता प्रबंधन में सक्षम है मॉडलों और विभिन्न स्थानों का ट्रैक रखने के लिए स्रोत कोड में एक सुविधा लागू की गई है।

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

0
जोड़ा

यदि आप सी ++ का उपयोग कर रहे हैं, तो क्या आपके ए, बी, और सी अनुप्रयोगों को एक सामान्य पूर्वजों से प्राप्त नहीं होना चाहिए? समस्या को हल करने के लिए ओओ रास्ता होगा।

0
जोड़ा
बी और सी की अतिरिक्त कार्यक्षमता प्रणाली के भीतर काफी 'गहरी' है, इसलिए यह एक छोटा बदलाव नहीं है। मुझे लगता है कि आप सही हैं कि एक ओओ दृष्टिकोण मदद कर सकता है (असल में मैं उस पर प्रतिक्रिया कर रहा था जब मैंने अपना साफ पैर उड़ाया)
जोड़ा लेखक Roddy, स्रोत

समस्या यह है कि एक ऐसे नाम के साथ #if निर्देश का उपयोग करना जो अनिर्धारित कार्य करता है जैसे कि इसे 0 के रूप में परिभाषित किया गया है। इसे पहले हमेशा #ifdef कर से बचा जा सकता है, लेकिन यह बोझिल और त्रुटि दोनों प्रवण है।

नेमस्पेस और नेमस्पेस एलियासिंग का उपयोग करने का थोड़ा बेहतर तरीका है।

जैसे

namespace AppA {
    //application A specific
}

namespace AppB {
   //application B specific
}

और नेमस्पेस एलियासिंग करने के लिए आपको app_defines.h का उपयोग करें

#if compiler_option_for_appA
     namespace Application = AppA;
#elif compiler_option_for_appB
     namespace Application = AppB;
#endif

या, यदि अधिक जटिल संयोजन, नामस्थान घोंसला

namespace Application
{
  #if compiler_option_for_appA
     using namespace AppA;
  #elif compiler_option_for_appB
     using namespace AppB;
  #endif
}

या उपर्युक्त का कोई संयोजन।

लाभ यह है कि जब आप हेडर भूल जाते हैं तो आपको अपने कंपाइलर i.s.o से अज्ञात नेमस्पेस त्रुटियां मिलेंगी। चुपचाप असफल होने के कारण आवेदन 0 को डिफॉल्ट किया गया है।

ऐसा कहा जा रहा है कि, मैं इसी तरह की स्थिति में रहा हूं, मैंने कई पुस्तकालयों में सब कुछ दोबारा करने का फैसला किया, जिसमें से अधिकांश बहुमत साझा किया गया था, और संस्करण नियंत्रण प्रणाली को विभिन्न अनुप्रयोगों में जहां कहीं भी जाता है, को संभालने दें। कोड में परिभाषित आदि पर भरोसा करते हैं।

यह मेरे opionon में थोड़ा बेहतर काम करता है, लेकिन मुझे पता है कि बहुत ही अनुप्रयोग विशिष्ट, वाईएमएमवी होता है।

0
जोड़ा

ऐसा कुछ करो:


CommonApp   +-----   AppExtender                        + = containment
                      ^    ^    ^
                      |    |    |                       ^ = ineritance
                    AppA  AppB  AppC                    |

Put your common code in the class CommonApp and put calls to the interface 'AppExtender' at strategic places. For example the AppExtender interface will have functions like afterStartup, afterConfigurationRead, beforeExit, getWindowTitle ...

फिर प्रत्येक एप्लिकेशन के मुख्य भाग में, सही विस्तारक बनाएं और इसे CommonApp पर पास करें:


    --- main_a.cpp

    CommonApp application;
    AppA appA;
    application.setExtender(&appA);
    application.run();

    --- main_a.cpp

    CommonApp application;
    AppB appB;
    application.setExtender(&appB);
    application.run();
0
जोड़ा

हालांकि, मैंने आज सुबह पैर में खुद को गोली मार दी और एक फ़ाइल से #include "app_defines.h" को लाइन को छोड़कर बहुत समय तक बर्बाद कर दिया। सब कुछ ठीक संकलित, लेकिन एप्लिकेशन स्टार्टअप पर एवीएस के साथ दुर्घटनाग्रस्त हो गया।

इस समस्या का एक सरल समाधान है, चेतावनियां चालू करें ताकि यदि APP_B परिभाषित नहीं किया गया है तो आपकी परियोजना संकलित नहीं होती है (या कम से कम पर्याप्त चेतावनियां उत्पन्न करती है ताकि आप जानते हों कि कुछ गलत है)।

0
जोड़ा
यह काम करेगा अगर मेरे कंपाइलर (सी ++ बिल्डर) ने चेतावनी को एक विकल्प के रूप में रखा था। यह नहीं है ...
जोड़ा लेखक Roddy, स्रोत

यह मुझे लगता है कि आप अलग-अलग संकलित तत्वों में अपने कोड को मॉड्यूलर करना, सामान्य मॉड्यूल के चयन से भिन्नताएं और एक प्रकार-विशिष्ट शीर्ष-स्तरीय (मुख्य) मॉड्यूल का निर्माण कर सकते हैं।

फिर इन हिस्सों में से कौन सा हिस्सा एक निर्माण में जाता है, जिसके द्वारा शीर्ष स्तर को संकलित करने और कौन सी .obj फ़ाइलों को आप लिंकर चरण में शामिल करने में हेडर फ़ाइलों का उपयोग किया जाता है।

आपको पहले यह थोड़ा सा संघर्ष मिल सकता है। लंबे समय तक आपके पास एक अधिक विश्वसनीय और सत्यापन योग्य निर्माण और रखरखाव प्रक्रिया होनी चाहिए। आपको सभी #if विविधताओं के बारे में चिंता किए बिना बेहतर परीक्षण करने में भी सक्षम होना चाहिए।

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

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

यह वही गेम है चाहे आप सी ++ कक्षाओं का उपयोग कर रहे हों या सी/सी ++ आम भाषा स्तर पर बहुत अधिक परिचालन कर रहे हों।

0
जोड़ा

जब कोई प्रीप्रोसेसर परिभाषित किया जाता है या नहीं, तो यह जानने की विशिष्ट तकनीकी समस्या को हल करने के लिए, एक सरल लेकिन प्रभावी चाल है।

के बजाय -

#define APP_A 0
#define APP_B 1
#define APP_C 2

उपयोग -

#define APP_A() 0
#define APP_B() 1
#define APP_C() 2

And in the place that queries for the version उपयोग -

#if APPLICATION >= APP_B()
// extra features for APPB and APP_C
#endif

(संभावित रूप से एक ही भावना में आवेदन के साथ कुछ करें)।

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

0
जोड़ा