স্থির শ্রেণীর সদস্যের অপরিজ্ঞাত রেফারেন্স


201

নিম্নলিখিত কোডটি সংকলন করবে না এমন কেউ কি ব্যাখ্যা করতে পারেন? কমপক্ষে g ++ 4.2.4 এ।

এবং আরও আকর্ষণীয়, আমি যখন সদস্যটিকে কাস্ট করব তখন এটি কেন সংকলন করবে?

#include <vector>

class Foo {  
public:  
    static const int MEMBER = 1;  
};

int main(){  
    vector<int> v;  
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

আমি <pre> <code> </code> </pre> ব্যবহার না করে চারটি স্পেস দিয়ে কোডটি প্রবেশ করার জন্য প্রশ্নটি সম্পাদনা করেছি। এর অর্থ কোণ বন্ধনীগুলি এইচটিএমএল হিসাবে ব্যাখ্যা করা হয় না।
স্টিভ জেসোপ

stackoverflow.com/questions/16284629/… আপনি এই প্রশ্নটি উল্লেখ করতে পারেন।
টুবা ইকবাল

উত্তর:


199

আপনাকে স্থির সদস্যকে কোথাও কোথাও নির্ধারণ করতে হবে (শ্রেণির সংজ্ঞার পরে)। এটা চেষ্টা কর:

class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }

এটি অপরিবর্তিত রেফারেন্স থেকে মুক্তি পাওয়া উচিত।


3
ভাল পয়েন্ট, ইনলাইন স্ট্যাটিক কনট সংখ্যার সূচনা একটি স্কোপড পূর্ণসংখ্যার ধ্রুবক তৈরি করে যার ঠিকানা আপনি নিতে পারবেন না এবং ভেক্টর একটি রেফারেন্স প্যারাম নেয়।
ইভান তেরান

10
এই উত্তরটি কেবল প্রশ্নের প্রথম অংশকেই সম্বোধন করে। দ্বিতীয় অংশটি আরও আকর্ষণীয়: একটি এনওপি কাস্ট যুক্ত করা বাহ্যিক ঘোষণার প্রয়োজন ছাড়াই কেন এটি কার্যকর করে?
নোটার

32
আমি স্রেফ এটি নির্ধারণ করতে বেশ ভাল সময় ব্যয় করেছি যে শ্রেণীর সংজ্ঞাটি যদি একটি শিরোনামের ফাইলে থাকে তবে স্থির পরিবর্তনশীলের বরাদ্দটি হ্যাডার নয়, বাস্তবায়ন ফাইলে থাকতে হবে।
শনিয়েট

1
@ শ্যাশনেট: খুব ভালো কথা - আমার উত্তরটি আমার উল্লেখ করা উচিত ছিল!
ড্রিউ হল

তবে যদি আমি এটিকে কনস্ট হিসাবে ঘোষণা করি তবে আমার পক্ষে কি এই ভেরিয়েবলের মান পরিবর্তন করা সম্ভব নয়?
নমরাথা

78

নতুন সি ++ বৈশিষ্ট্যগুলির আকর্ষণীয় সংঘর্ষ এবং আপনি যা করার চেষ্টা করছেন তার ফলেই সমস্যাটি এসেছে। প্রথমে push_backস্বাক্ষরটি একবার দেখুন :

void push_back(const T&)

এটি টাইপের কোনও অবজেক্টের রেফারেন্স আশা করে T। পুরানো প্রারম্ভিক পদ্ধতির অধীনে, এই জাতীয় সদস্য উপস্থিত রয়েছে। উদাহরণস্বরূপ, নিম্নলিখিত কোডগুলি ঠিক জরিমানা সংকলন করেছে:

#include <vector>

class Foo {
public:
    static const int MEMBER;
};

const int Foo::MEMBER = 1; 

int main(){
    std::vector<int> v;
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

এটি কারণ যেখানে কোথাও একটি আসল অবজেক্ট রয়েছে যার মধ্যে এটির মান রয়েছে। তবে, আপনি যদি স্ট্যাটিক কনস্টের সদস্যদের নির্দিষ্ট করে দেওয়ার নতুন পদ্ধতিটিতে স্যুইচ করেন তবে আপনার উপরে Foo::MEMBERযেমন রয়েছে তেমনি কোনও বস্তু নেই। এটি একটি ধ্রুবক, কিছুটা সদৃশ:

#define MEMBER 1

তবে প্রিপ্রেসেসর ম্যাক্রোর মাথা ব্যথা ছাড়াই (এবং প্রকারের সুরক্ষা সহ)। এর অর্থ হ'ল ভেক্টর, যা একটি রেফারেন্সের প্রত্যাশা করছে, এটি পেতে পারে না।


2
ধন্যবাদ, যে সাহায্য করেছে ... যে জন্য যোগ্যতা অর্জন করতে পারে stackoverflow.com/questions/1995113/strangest-language-feature যদি না সেখানে আগে থেকেই ...
আন্দ্রে Holzner

1
এছাড়াও লক্ষণীয় যে এমএসভিসি অভিযোগ ছাড়াই নন-কাস্ট সংস্করণ গ্রহণ করে।
ছুঁড়েছে

4
-1: এটি কেবল সত্য নয়। স্থির সদস্যরা ইনলাইজ করা প্রাথমিকভাবে সদস্যদের সংজ্ঞায়িত করার কথা রয়েছে, যখন তারা কোথাও অদ্ভুত-ব্যবহৃত হয় । এই সংকলক অপটিমাইজেশন আপনার লিঙ্কার ত্রুটি থেকে মুক্তি পেতে পারে যে এটি পরিবর্তন করে না। এক্ষেত্রে আপনার মূল্য-থেকে-মূল্যকে রূপান্তর (অভিনেতাদের ধন্যবাদ (int)) ধ্রুবকের নিখুঁত দৃশ্যমানতার সাথে অনুবাদ ইউনিটে ঘটে এবং এটি Foo::MEMBERআর অদ্ভুত-ব্যবহৃত হয় না । এটি প্রথম ফাংশন কলের বিপরীতে, যেখানে একটি রেফারেন্স চারপাশে পাস করা হয় এবং অন্য কোথাও মূল্যায়ন করা হয়।
হালকাতা রেস

কি হবে void push_back( const T& value );? const&এর সাথে মূল্যবোধের সাথে আবদ্ধ থাকতে পারে।
Kostas

59

সি ++ স্ট্যান্ডার্ডের জন্য আপনার স্ট্যাটিক কনস্ট সদস্যের জন্য একটি সংজ্ঞা প্রয়োজন যদি সংজ্ঞাটি কোনওরকম প্রয়োজন হয়।

সংজ্ঞাটি প্রয়োজনীয়, উদাহরণস্বরূপ যদি এটি ঠিকানা ব্যবহার করা হয়। push_backকনস্ট্রাক্ট রেফারেন্স অনুসারে এর প্যারামিটারটি নেয় এবং তাই কঠোরভাবে সংকলকটির আপনার সদস্যের ঠিকানা প্রয়োজন এবং আপনাকে এটি নেমস্পেসে সংজ্ঞায়িত করতে হবে।

আপনি যখন স্পষ্টভাবে ধ্রুবকটি নিক্ষেপ করেন, আপনি একটি অস্থায়ী তৈরি করছেন এবং এটি এই অস্থায়ী যা রেফারেন্সের সাথে আবদ্ধ (আদর্শের বিশেষ নিয়মের অধীনে)।

এটি সত্যিই একটি আকর্ষণীয় কেস এবং আমি আসলেই মনে করি এটি একটি বিষয় উত্থাপনের পক্ষে মূল্যবান যাতে আপনার ধ্রুবক সদস্যের সাথে একই আচরণ করার জন্য স্ট্যান্ডার্ডটি পরিবর্তন করা যায়!

যদিও, একটি অদ্ভুত উপায়ে এটিকে ইউনারি '+' অপারেটরের বৈধ ব্যবহার হিসাবে দেখা যেতে পারে। মূলত unary +ফলাফলটির ফলাফল একটি মূল্যায়ন এবং সুতরাং রেফালিউসগুলি রেফারেন্সের জন্য বাইরের রেফারেন্সগুলি প্রযোজ্য এবং আমরা আমাদের স্থিতিশীল সদস্যের ঠিকানা ব্যবহার করি না:

v.push_back( +Foo::MEMBER );

3
+1 টি। হ্যাঁ এটি অবশ্যই অদ্ভুত যে টাইপের টির জন্য একটি অবজেক্ট এক্স এর জন্য "(টি) x" এক্সপ্রেশনটি কনস্টের রেফ বাঁধতে ব্যবহার করা যেতে পারে যখন সরল "এক্স" করতে পারে না। আমি "unary +" সম্পর্কে আপনার পর্যবেক্ষণ পছন্দ করি! কে ভেবেছিল যে দরিদ্র ছোট "আনরিয়া +" আসলে ব্যবহার করেছে ... :)
j_random_hacker

3
সাধারণ কেস সম্পর্কে চিন্তাভাবনা ... সি ++ তে অন্য কোনও ধরণের অবজেক্টের কী সম্পত্তি রয়েছে যা এটি (1) কেবলমাত্র সংজ্ঞাযুক্ত থাকলে তবে (2) একটি লভ্যালু হিসাবে ব্যবহার করা যেতে পারে তবে (2) না হয়ে কোনও মূল্যকে রূপান্তর করা যায় সংজ্ঞায়িত?
j_random_hacker

ভাল প্রশ্ন, এবং এই মুহূর্তে আমি অন্য কোনও উদাহরণের কথা ভাবতে পারি না। এটি সম্ভবত এখানেই কারণ কমিটি বেশিরভাগই কেবল বিদ্যমান বাক্য গঠনটিকে পুনরায় ব্যবহার করছিল।
রিচার্ড কর্ডেন

@ রিচার্ডকার্ডেন: অ্যানারি কীভাবে সমাধান করেছে?
রক্ত-হাজ্জারা

1
@ ব্লাড-হ্যাজআরডিডি: মূল্যবোধের রেফারেন্সগুলির আগে একমাত্র ওভারলোড push_backছিল a const &। সদস্যটি সরাসরি ব্যবহারের ফলে সদস্যটি রেফারেন্সের সাথে আবদ্ধ হতে পারে, যার প্রয়োজন ছিল এটির একটি ঠিকানা। তবে, সংযোজন +সদস্যের মান সহ একটি অস্থায়ী তৈরি করে। এরপরে রেফারেন্সটি সদস্যের একটি ঠিকানা থাকা প্রয়োজনের চেয়ে সেই অস্থায়ী সাথে আবদ্ধ।
রিচার্ড কর্ডেন

10

Aaa.h

class Aaa {

protected:

    static Aaa *defaultAaa;

};

Aaa.cpp

// You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;

1

Castালাই কেন কাজ করে তা ধারণা নেই তবে ফু :: প্রথমবার ফু লো লোড না হওয়া পর্যন্ত সদস্য বরাদ্দ দেওয়া হয়নি এবং আপনি কখনই এটি লোড করছেন না, এটি কখনই বরাদ্দ দেওয়া হয় না। আপনার যদি কোথাও কোনও ফু সম্পর্কিত একটি রেফারেন্স থাকে তবে এটি সম্ভবত কার্যকর হবে।


আমি মনে করি আপনি নিজের প্রশ্নের উত্তর দিচ্ছেন: castালাই কাজ করে কারণ এটি (একটি অস্থায়ী) রেফারেন্স তৈরি করে।
জাপ ভার্সটিঘ

1

সি ++ 11 দিয়ে উপরেরগুলি মৌলিক ধরণের জন্য সম্ভব হবে

class Foo {
public:  
  static constexpr int MEMBER = 1;  
};

constexprঅংশ একটি স্ট্যাটিক সৃষ্টি অভিব্যক্তি হিসাবে একটি স্ট্যাটিক বিরোধিতা পরিবর্তনশীল শুধু একটি অত্যন্ত সহজ ইনলাইন পদ্ধতি সংজ্ঞা মতো আচরণ করবে এবং -। যদিও টেমপ্লেট শ্রেণীর অভ্যন্তরে সি-স্ট্রিং কনটেক্সারদের সাথে এই পদ্ধতির কিছুটা ঝাঁকুনির প্রমাণ হয়েছিল।


এটি আমার জন্য অপরিহার্য হিসাবে প্রমাণিত হয়েছিল, কারণ "স্ট্যাটিক কনট ইন মেম্বার = 1;" স্যুইচগুলিতে মেমবার ব্যবহার করার প্রয়োজন রয়েছে, যখন এটি বাহ্যিক ঘোষণার জন্য এটি ভেক্টরগুলিতে ব্যবহার করার প্রয়োজন হয় এবং আপনার উভয় একই সময়ে থাকতে পারে না। আপনি এখানে যে মত প্রকাশ করেন তা কমপক্ষে আমার সংকলক সহ উভয়ের পক্ষে কাজ করে
বেন ফার্মার

0

দ্বিতীয় প্রশ্ন সম্পর্কিত: পুশ_রেফ প্যারামিটার হিসাবে রেফারেন্স নেয় এবং আপনার কোনও শ্রেণি / কাঠামোর স্ট্যাটিক কনস্ট মেম্বারের রেফারেন্স থাকতে পারে না। আপনি একবার স্ট্যাটিক_কাস্ট কল করলে একটি অস্থায়ী পরিবর্তনশীল তৈরি হয় is এবং এই বস্তুর একটি রেফারেন্স পাস করা যেতে পারে, সবকিছু ঠিকঠাক কাজ করে।

বা কমপক্ষে আমার সহকর্মী যিনি এটি সমাধান করেছেন তিনি তাই বলেছিলেন।

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