সি ++ এ নেস্টেড টাইপ / ক্লাসের ফরোয়ার্ড ঘোষণা


197

আমি সম্প্রতি এমন পরিস্থিতিতে আটকে গিয়েছি:

class A
{
public:
    typedef struct/class {...} B;
...
    C::D *someField;
}

class C
{
public:
    typedef struct/class {...} D;
...
    A::B *someField;
}

সাধারণত আপনি একটি শ্রেণীর নাম ঘোষণা করতে পারেন:

class A;

তবে আপনি নেস্টেড প্রকারটি ঘোষণা করতে পারবেন না, নিম্নলিখিত সংকলনের ত্রুটির কারণ রয়েছে।

class C::D;

কোন ধারনা?


6
তোমার এতো দরকার কেন? নোট করুন যে আপনি ঘোষণা করতে এগিয়ে যেতে পারেন যদি এটি একই শ্রেণীর সদস্য সংজ্ঞায়িত করা হয়: দশম {শ্রেনী Y; Y * a; }; দশম শ্রেণি :: Y {};
জোহানেস স্কাউব - লিটব

এই সমাধান আমার জন্য কাজ (নামস্থান সি {বর্গ ডি;}) stackoverflow.com/questions/22389784/...
আলবার্ট Wiersch

আমি একটি সমাধান লিঙ্কটি
বিটল্সি

উত্তর:


224

আপনি এটি করতে পারবেন না, এটি সি ++ ভাষার একটি গর্ত। নেস্টেড ক্লাসগুলির অন্তত একটিতে আপনাকে বাসা বেঁধে ফেলতে হবে।


6
উত্তর করার জন্য ধন্যবাদ. আমার ক্ষেত্রে, তারা আমার নেস্টেড ক্লাস নয়। আমি আশা করছিলাম একটি সামান্য সামনের দিকে উল্লেখ সহ একটি বিশাল গ্রন্থাগার শিরোনাম ফাইল নির্ভরতা এড়ানোর জন্য। আমি ভাবছি যদি সি ++ 11 এটি স্থির করে?
মার্শ রে

61
উহু. আমি গুগলটি কী দেখাতে চাইনি। সংক্ষিপ্ত উত্তরের জন্য যাইহোক ধন্যবাদ।
learnvst

19
এখানেও ... কেউ কি জানেন কেন এটি সম্ভব নয়? দেখে মনে হচ্ছে বৈধ ব্যবহারের কেস রয়েছে এবং এই অভাব কিছু পরিস্থিতিতে আর্কিটেকচারের ধারাবাহিকতা রোধ করে।
মল নিসন

আপনি বন্ধু ব্যবহার করতে পারেন। এবং কেবল একটি মন্তব্য দিন যাতে আপনি এটি সি ++ এর গর্তটি ঘিরে কাজ করতে ব্যবহার করছেন।
এরিক অ্যারোনস্টি

3
আমি যখনই এর্সতজ ভাষায় এ জাতীয় অপ্রয়োজনীয় ত্রুটিগুলির মুখোমুখি হই তখনই আমি হাসি এবং কাঁদতে কাঁদতে
থাকি

33
class IDontControl
{
    class Nested
    {
        Nested(int i);
    };
};

আমার এর মতো ফরওয়ার্ড রেফারেন্স দরকার:

class IDontControl::Nested; // But this doesn't work.

আমার কাজটি ছিল:

class IDontControl_Nested; // Forward reference to distinct name.

পরে যখন আমি সম্পূর্ণ সংজ্ঞাটি ব্যবহার করতে পারি:

#include <idontcontrol.h>

// I defined the forward ref like this:
class IDontControl_Nested : public IDontControl::Nested
{
    // Needed to make a forwarding constructor here
    IDontControl_Nested(int i) : Nested(i) { }
};

জটিল কন্সট্রাক্টর বা অন্যান্য বিশেষ সদস্য ফাংশনগুলি ছিল যা উত্তমভাবে উত্তরাধিকার সূত্রে প্রাপ্ত হয় নি যদি এই কৌশলটি সম্ভবত এটির চেয়ে বেশি সমস্যা হয় be আমি কিছু টেমপ্লেট যাদু খারাপ প্রতিক্রিয়া করতে পারে কল্পনা করতে পারেন।

তবে আমার খুব সাধারণ ক্ষেত্রে, এটি কাজ করে বলে মনে হচ্ছে।


16
সি ++ 11 এ আপনি using basename::basename;উদ্ভূত শ্রেণিতে কন্সট্রাক্টরদের উত্তরাধিকারী হতে পারেন , এইভাবে জটিল সেন্টারে কোনও সমস্যা নেই।
Xoo

1
দুর্দান্ত কৌশল, তবে আইডন্টকন্ট্রোলকে নির্দেশক :: একই শিরোনামের মধ্যে নেস্টেড ব্যবহার করা হয়েছে (যেখানে এটি এগিয়ে ঘোষণা করা হয়েছে) এবং বাইরের কোড থেকে অ্যাক্সেস করা হয়েছে যাতে আইডন্টকন্ট্রোলের সম্পূর্ণ সংজ্ঞাও রয়েছে। (কারণ সংকলক আইডন্টকন্ট্রোল_ নেস্টেড এবং আইডন্টকন্ট্রোল :: নেস্টেডের সাথে মেলে না)। ওয়ার্কআরউন্ড স্ট্যাটিক কাস্ট অভিনয় করা হয়।
আর্টেম পিসারেঙ্কো

আমি উল্টোটি করার এবং ক্লাসের বাইরে থাকার পরামর্শ দিয়েছি এবং কেবল typedefক্লাসের মধ্যেই ব্যবহার করব
রাইডারহফ

3

আপনি যদি সত্যিই আপনার শিরোনামের ফাইলটিতে দুষ্টু শিরোনাম ফাইলটি অন্তর্ভুক্ত করতে চান তবে আপনি এটি করতে পারেন:

এইচপিপি ফাইল:

class MyClass
{
public:
    template<typename ThrowAway>
    void doesStuff();
};

সিপিপি ফাইল

#include "MyClass.hpp"
#include "Annoying-3rd-party.hpp"

template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>()
{
    // ...
}

কিন্তু তারপর:

  1. আপনাকে কল সময়ে এমবেডেড প্রকারটি নির্দিষ্ট করতে হবে (বিশেষত যদি আপনার ফাংশন এমবেডেড ধরণের কোনও প্যারামিটার না নেয়)
  2. আপনার ফাংশন ভার্চুয়াল হতে পারে না (কারণ এটি একটি টেম্পলেট)

তো, হ্যাঁ, ট্রেড অফস ...


1
হেক একটি hppফাইল কি?
নফতালি ওরফে নীল

7
লল , একটি .hpp শিরোলেখ ফাইলটি সি ++ প্রকল্পে এটি একটি সি শিরোনাম ফাইল থেকে আলাদা করতে ব্যবহৃত হয় যা সাধারণত .h দিয়ে শেষ হয়। একই প্রকল্পে সি ++ এবং সি নিয়ে কাজ করার সময় কিছু লোক সি ++ ফাইলগুলির জন্য .hpp এবং .cpp পছন্দ করেন, যাতে তারা কী ধরণের ফাইলের সাথে ডিল করে এবং সি এইচ।
বিটেক

2

এটি বাহ্যিক শ্রেণীর নাম স্থান হিসাবে ঘোষণা করে এগিয়ে নেওয়া যায়

নমুনা: আমাদের একটি নেস্টেড শ্রেণি অন্যদের ব্যবহার করতে হবে :: এ :: অন্যদের মধ্যে নেস্টেড_এইচ, যা আমাদের নিয়ন্ত্রণের বাইরে।

others_a.h

namespace others {
struct A {
    struct Nested {
        Nested(int i) :i(i) {}
        int i{};
        void print() const { std::cout << i << std::endl; }
    };
};
}

my_class.h

#ifndef MY_CLASS_CPP
// A is actually a class
namespace others { namespace A { class Nested; } }
#endif

class MyClass {
public:
    MyClass(int i);
    ~MyClass();
    void print() const;
private:
    std::unique_ptr<others::A::Nested> _aNested;
};

my_class.cpp

#include "others_a.h"
#define MY_CLASS_CPP // Must before include my_class.h
#include "my_class.h"

MyClass::MyClass(int i) :
    _aNested(std::make_unique<others::A::Nested>(i)) {}
MyClass::~MyClass() {}
void MyClass::print() const {
    _aNested->print();
}

1
এটি কাজ করতে পারে, তবে এটি অনথিভুক্ত। এটি কাজ করার কারণটি a::bহ'ল একইভাবে ম্যাঙ্গেল করা হয়, aশ্রেণি বা নেমস্পেস যাই হোক না কেন ।
jaskmar

3
ঝনঝন বা জিসিসির সাথে কাজ করে না। এটি বলে যে বহিরাগত শ্রেণিটিকে একটি নেমস্পেসের চেয়ে আলাদা কিছু হিসাবে ঘোষণা করা হয়েছিল।
ডুগি

1

আমি এটিকে কোনও উত্তর বলব না, তবে এটি একটি আকর্ষণীয় সন্ধান: আপনি যদি নিজের কাঠামোর ঘোষণাকে সি নামক স্থানে পুনরাবৃত্তি করেন তবে সবকিছু ঠিক আছে (কমপক্ষে জিসিসিতে)। C এর শ্রেণি সংজ্ঞা পাওয়া গেলে, মনে হয় নিঃশব্দে নামস্পেস সিটিকে ওভাররাইট করে to

namespace C {
    typedef struct {} D;
}

class A
{
public:
 typedef struct/class {...} B;
...
C::D *someField;
}

class C
{
public:
   typedef struct/class {...} D;
...
   A::B *someField;
}

1
আমি সাইগউইন জিসিসি দিয়ে এটি চেষ্টা করেছি এবং আপনি এ.সোমফিল্ডের রেফারেন্স দেওয়ার চেষ্টা করলে এটি সংকলন করে না। সি :: ডি ক্লাসে ডি সংজ্ঞা আসলে নেমস্পেসের (খালি) স্ট্রাক্টকে বোঝায়, ক্লাস সি-তে স্ট্রাক্ট নয় (বিটিডব্লিউ এটি এমএসভিসিতে সংকলন করে না)
ডলফিন

এটি ত্রুটিটি দেয়: "'শ্রেণি সি' বিভিন্ন ধরণের প্রতীক হিসাবে
পুনরায় ঘোষিত হয়েছে

9
দেখতে একটি জিসিসি বাগের মতো। মনে হচ্ছে কোনও নেমস্পেসের নাম একই শ্রেণিতে একটি শ্রেণীর নাম গোপন করতে পারে।
জোহানেস স্কাউব - লিটব

0

এটি হ'ল একটি সমাধান (কমপক্ষে প্রশ্নে বর্ণিত সমস্যার জন্য - আসল সমস্যার জন্য নয়, যেমন, যখন সংজ্ঞাটির উপরে নিয়ন্ত্রণ না রাখে C):

class C_base {
public:
    class D { }; // definition of C::D
    // can also just be forward declared, if it needs members of A or A::B
};
class A {
public:
    class B { };
    C_base::D *someField; // need to call it C_base::D here
};
class C : public C_base { // inherits C_base::D
public:
    // Danger: Do not redeclare class D here!!
    // Depending on your compiler flags, you may not even get a warning
    // class D { };
    A::B *someField;
};

int main() {
    A a;
    C::D * test = a.someField; // here it can be called C::D
}

0

আপনার যদি সি এবং ডি ক্লাসের উত্স কোডটি পরিবর্তন করার অ্যাক্সেস থাকে তবে আপনি ডি ক্লাসটি আলাদাভাবে নিতে পারেন এবং সি শ্রেণিতে এর প্রতিশব্দ লিখতে পারেন:

class CD {

};

class C {
public:

    using D = CD;

};

class CD;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.