C ++ में एक टंकण की घोषणा


235

संकलक मुझे आगे टाइपपैड घोषित करने की अनुमति क्यों नहीं देगा?

यह असंभव है, यह मानते हुए कि मेरे समावेश के पेड़ को छोटा रखने के लिए सबसे अच्छा अभ्यास क्या है?

जवाबों:


170

आप आगे टाइप टाइप कर सकते हैं। लेकिन करने के लिए

typedef A B;

आपको पहले घोषणा करनी चाहिए A:

class A;

typedef A B;

11
अंत में +1 क्योंकि जब आप तकनीकी रूप से "फॉरवर्ड-टाइपडिफ" नहीं कर सकते हैं (यानी आप "टाइपडिफ .." नहीं लिख सकते हैं), तो आप लगभग निश्चित रूप से पूरा कर सकते हैं कि ओपी अपनी चाल का उपयोग करके क्या हासिल करना चाहता है।
j_random_hacker 7

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

50
सामान्य तौर पर यह एक उपयोगी समाधान नहीं है। उदाहरण के लिए यदि typedefनाम एक जटिल बहुस्तरीय टेम्पलेट प्रकार आगे घोषणा का उपयोग करते हुए इस तरह जटिल और कठिन है। यह उल्लेख करने के लिए नहीं कि इसे डिफ़ॉल्ट टेम्पलेट तर्कों में छिपे कार्यान्वयन विवरण में गोताखोरी की आवश्यकता हो सकती है। और अंत समाधान एक लंबा और अपठनीय कोड है (विशेषकर जब प्रकार विभिन्न नामस्थानों से आते हैं) मूल प्रकार में बदलने के लिए बहुत प्रवण हैं।
एडम बदुरा 12

3
इसके अलावा यह "कार्यान्वयन विवरण" दिखाता है (भले ही पूरी तरह से लेकिन अभी भी नहीं ...) जबकि आगे की घोषणा के पीछे का विचार उन्हें छिपाना था।
एडम बदुरा 12

3
@वाइंडफाइंडर: यह करता है: टेम्पलेट <वर्ग T> वर्ग A; टाइम्डिफ ए <सी> बी;
मिलियनव

47

आप में से मेरे जैसे उन लोगों के लिए, जो आगे देख रहे हैं कि एक सी-शैली की संरचना घोषित की गई है जिसे टाइप सीड का उपयोग करके परिभाषित किया गया था, कुछ सी ++ कोड में, मैंने एक समाधान पाया है जो निम्नानुसार है ...

// a.h
 typedef struct _bah {
    int a;
    int b;
 } bah;

// b.h
 struct _bah;
 typedef _bah bah;

 class foo {
   foo(bah * b);
   foo(bah b);
   bah * mBah;
 };

// b.cpp
 #include "b.h"
 #include "a.h"

 foo::foo(bah * b) {
   mBah = b;
 }

 foo::foo(bah b) {
   mBah = &b;
 }

4
@LittleJohn इस समाधान के साथ समस्या यह है कि डमी-नाम _bah को सार्वजनिक API का हिस्सा नहीं माना जाता है। आगे देखें delcare FILE
user877329

23

"Fwd एक टाइपराइड घोषित करने के लिए" आपको एक वर्ग या एक संरचना घोषित करने की आवश्यकता है और फिर आप टाइप किए गए प्रकार को टाइप कर सकते हैं। संकलक द्वारा एकाधिक समान टाइपडेफ स्वीकार्य हैं।

लंबा फार्म:

class MyClass;
typedef MyClass myclass_t;

संक्षिप्त रूप:

typedef class MyClass myclass_t;

यह सबसे अधिक मतदान वाले प्रश्न से कैसे भिन्न है? stackoverflow.com/a/804956/931303
जॉर्ज लेइताओ

1
@ JorgeLeitão आप यह नहीं देखते कि यह कैसे अलग है? यह नहीं दिखाता कि एक पंक्ति में ऐसा कैसे किया जाए।
पावेल पी।

17

C ++ में (लेकिन सादा सी नहीं), यह एक प्रकार का दो बार टाइप करने के लिए पूरी तरह से कानूनी है, इसलिए जब तक दोनों परिभाषाएं पूरी तरह से समान नहीं होती हैं:

// foo.h
struct A{};
typedef A *PA;

// bar.h
struct A;  // forward declare A
typedef A *PA;
void func(PA x);

// baz.cc
#include "bar.h"
#include "foo.h"
// We've now included the definition for PA twice, but it's ok since they're the same
...
A x;
func(&x);

34
अनुरक्षण संख्या नहीं। इस तरह की चीज आपको जल्द या बाद में कीिस्टर में काट लेगी।
मार्क स्टॉपर

3
@MarkStorer, कम से कम कंपाइलर किसी भी अंतर को पकड़ लेगा और एक त्रुटि उत्पन्न करेगा। मैंने इसे विजुअल C ++ से सत्यापित किया।
एलन

अच्छा लगा, लेकिन परिभाषा के अनुसार खाली होने के Aबाद आप इस तरह से खेतों को कैसे परिभाषित करते हैं A?
पेट्रीज़ियो बर्तोनी

10

क्योंकि एक प्रकार की घोषणा करने के लिए, इसके आकार को जानना आवश्यक है। आप आगे एक सूचक को टाइप करने के लिए घोषित कर सकते हैं, या टाइप करने के लिए एक पॉइंटर को टाइप कर सकते हैं।

यदि आप वास्तव में चाहते हैं, तो आप नीचे दिए गए रखने के लिए pimpl मुहावरे का उपयोग कर सकते हैं। लेकिन अगर आप पॉइंटर के बजाय एक प्रकार का उपयोग करना चाहते हैं, तो संकलक को इसका आकार जानना होगा।

संपादित करें: j_random_hacker इस उत्तर के लिए एक महत्वपूर्ण योग्यता जोड़ता है, मूल रूप से आकार का उपयोग करने के लिए पता होना चाहिए , लेकिन एक आगे की घोषणा की जा सकती है यदि हमें केवल पता होना चाहिए कि मौजूद है , तो संकेत या संदर्भ बनाने के लिए। प्रकार। चूंकि ओपी ने कोड नहीं दिखाया था, लेकिन शिकायत की थी कि यह संकलन नहीं होगा, मैंने माना (शायद सही ढंग से) कि ओपी प्रकार का उपयोग करने की कोशिश कर रहा था , न कि केवल इसका संदर्भ लें।


35
खैर, वर्ग प्रकारों की आगे की घोषणाएं इन प्रकारों को उनके आकार के ज्ञान के बिना घोषित करती हैं। इसके अलावा, ऐसे अपूर्ण प्रकारों के लिए संकेत और संदर्भों को परिभाषित करने में सक्षम होने के अलावा, फ़ंक्शंस घोषित किए जा सकते हैं (लेकिन परिभाषित नहीं) जो मापदंडों को लेते हैं और / या ऐसे प्रकारों का मान लौटाते हैं।
j_random_hacker

3
क्षमा करें, मुझे नहीं लगता कि यह एक अच्छी धारणा है। यह उत्तर बिंदु के बगल में है। यह बहुत ही आगे की घोषणा के लिए typedef का मामला है।
कुकी

6

पूर्ण एस के बजाय आगे की घोषणाओं का उपयोग करना #includeकेवल तभी संभव है जब आप स्वयं (इस फ़ाइल के दायरे में) प्रकार का उपयोग करने का इरादा नहीं कर रहे हैं, लेकिन एक संकेतक या इसके संदर्भ में।

स्वयं प्रकार का उपयोग करने के लिए, संकलक को इसका आकार पता होना चाहिए - इसलिए इसकी पूर्ण घोषणा को देखना होगा - इसलिए पूर्ण #includeकी आवश्यकता है।

हालाँकि, पॉइंटर या संदर्भ का आकार कंपाइलर के लिए जाना जाता है, चाहे पॉइंटर के आकार की परवाह किए बिना, इसलिए एक आगे की घोषणा पर्याप्त है - यह एक प्रकार का पहचानकर्ता नाम घोषित करता है।

दिलचस्प बात यह है कि जब पॉइंटर या संदर्भों classया structप्रकारों का उपयोग किया जाता है , तो कंपाइलर अपूर्ण प्रकारों को संभाल सकता है जो आपको आगे पॉइंटर प्रकारों को घोषित करने की आवश्यकता को बचा सकता है:

// header.h

// Look Ma! No forward declarations!
typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere
typedef class A& ARef;

typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere
typedef struct B& BRef;

// Using the name without the class/struct specifier requires fwd. decl. the type itself.    
class C;         // fwd. decl. type
typedef C* CPtr; // no class/struct specifier 
typedef C& CRef; // no class/struct specifier 

struct D;        // fwd. decl. type
typedef D* DPtr; // no class/struct specifier 
typedef D& DRef; // no class/struct specifier 

2

मेरे पास एक ही मुद्दा था, अलग-अलग फाइलों में कई टाइपडिफ के साथ गड़बड़ नहीं करना चाहता था, इसलिए मैंने इसे विरासत के साथ हल किया:

था:

class BurstBoss {

public:

    typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...

किया:

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{

public:

    ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
    };
};

एक जादू की तरह काम किया। बेशक, मुझे किसी भी संदर्भ को बदलना पड़ा

BurstBoss::ParticleSystem

बस करने के लिए

ParticleSystem

1

मैंने इनहेरिटेंस और कंस्ट्रक्टर इनहेरिटेंस (?) के साथ typedef( usingविशिष्ट होने के लिए) को प्रतिस्थापित किया ।

मूल

using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;

जगह ले ली

struct CallStack // Not a typedef to allow forward declaration.
  : public std::array<StackFrame, MAX_CALLSTACK_DEPTH>
{
  typedef std::array<StackFrame, MAX_CALLSTACK_DEPTH> Base;
  using Base::Base;
};

इस तरह मैं आगे घोषणा करने में सक्षम था CallStack:

class CallStack;

0

जैसा कि बिल कोट्सिया ने उल्लेख किया है, अपनी बात को निजी तौर पर टाइप करने के लिए रखने का एकमात्र उचित तरीका है, और आगे की घोषणा उन्हें विरासत के साथ करना है। यद्यपि आप इसे C ++ 11 के साथ थोड़ा अच्छा कर सकते हैं। इस पर विचार करो:

// LibraryPublicHeader.h

class Implementation;

class Library
{
...
private:
    Implementation* impl;
};
// LibraryPrivateImplementation.cpp

// This annoyingly does not work:
//
//     typedef std::shared_ptr<Foo> Implementation;

// However this does, and is almost as good.
class Implementation : public std::shared_ptr<Foo>
{
public:
    // C++11 allows us to easily copy all the constructors.
    using shared_ptr::shared_ptr;
};

0

@BillKotsias की तरह, मैंने विरासत का उपयोग किया, और इसने मेरे लिए काम किया।

मैंने इस गड़बड़ी को बदल दिया (जिसे मेरी घोषणा * .h में सभी बूस्टर हेडर की आवश्यकता थी)

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>

typedef boost::accumulators::accumulator_set<float,
 boost::accumulators::features<
  boost::accumulators::tag::median,
  boost::accumulators::tag::mean,
  boost::accumulators::tag::min,
  boost::accumulators::tag::max
 >> VanillaAccumulator_t ;
std::unique_ptr<VanillaAccumulator_t> acc;

इस घोषणा में (* .h)

class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;

और कार्यान्वयन (*। cpp) था

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>

class VanillaAccumulator : public
  boost::accumulators::accumulator_set<float,
    boost::accumulators::features<
      boost::accumulators::tag::median,
      boost::accumulators::tag::mean,
      boost::accumulators::tag::min,
      boost::accumulators::tag::max
>>
{
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.