আমি কেন ক্লাসে নন-কনস্ট্যান্ট স্ট্যাটিক সদস্য বা স্ট্যাটিক অ্যারে শুরু করতে পারি না?


116

আমি কেন কোনও ক্লাসে নন-কনস্ট্যান্ট staticসদস্য বা staticঅ্যারে শুরু করতে পারি না ?

class A
{
    static const int a = 3;
    static int b = 3;
    static const int c[2] = { 1, 2 };
    static int d[2] = { 1, 2 };
};

int main()
{
    A a;

    return 0;
}

সংকলক নিম্নলিখিত ত্রুটিগুলি ইস্যু করে:

g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member b
main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type const int [2]’
main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type int [2]’

আমার দুটি প্রশ্ন আছে:

  1. আমি কেন staticক্লাসে ডেটা সদস্যদের আরম্ভ করতে পারি না ?
  2. আমি কেন staticক্লাসে অ্যারে, এমনকি অ্যারে শুরু করতে পারি না const?

1
আমি মনে করি মূল কারণ এটি সঠিকভাবে পাওয়া কঠিন। নীতিগতভাবে, আপনি সম্ভবত যা বলছেন তা করতে পারেন তবে কিছু অদ্ভুত পার্শ্ব প্রতিক্রিয়া থাকতে পারে। আপনার অ্যারের উদাহরণটিকে যদি অনুমতি দেওয়া হয় তবে আপনি A :: c [0] এর মান পেতে সক্ষম হতে পারেন তবে A :: c কে কোনও ফাংশনে পাস করতে সক্ষম হবেন না কারণ এর জন্য একটি ঠিকানা প্রয়োজন এবং সংকলন-সময় দরকার ধ্রুবকের কোনও ঠিকানা নেই। সি ++ 11 কনস্টেক্সপ্রের ব্যবহারের মাধ্যমে এর কিছু সক্ষম করেছে।
ভোঁ ক্যাটো

দুর্দান্ত প্রশ্ন এবং উত্তর উত্তর। লিঙ্কটি যা আমাকে সহায়তা করেছে: msdn.microsoft.com/en-us/library/0e5kx78b.aspx
ETFovac

উত্তর:


144

আমি কেন staticক্লাসে ডেটা সদস্যদের আরম্ভ করতে পারি না ?

সি ++ স্ট্যান্ডার্ড ক্লাসের অভ্যন্তরে কেবল স্থিতিশীল ধ্রুবক অবিচ্ছেদ্য বা গণনা প্রকারকে মঞ্জুরি দেয়। aঅন্যদের না থাকলেই এই কারণটি শুরু করার অনুমতি দেওয়া হয়।

তথ্যসূত্র:
সি ++ 03 9.4.2 স্ট্যাটিক ডেটা সদস্য
-4 §

স্থিতিশীল ডেটা সদস্য যদি কনস্টিভ ইন্টিগ্রাল বা কনস্টের গণনা প্রকারের হয়, শ্রেণির সংজ্ঞাতে এর ঘোষণার ফলে একটি ধ্রুবক-আরম্ভকারী নির্দিষ্ট করা যায় যা একটি অবিচ্ছেদ্য ধ্রুবক প্রকাশ (5.19) হবে। সেক্ষেত্রে সদস্যটি অবিচ্ছেদ্য ধ্রুবক প্রকাশে উপস্থিত হতে পারে। সদস্যটি প্রোগ্রামে ব্যবহৃত হয় এবং নাম স্থানের স্কোপ সংজ্ঞাটিতে কোনও প্রাথমিককরণ উপস্থিত না থাকলে সদস্যের নাম স্পেস স্কোপে এখনও সংজ্ঞায়িত করা হবে।

অবিচ্ছেদ্য প্রকারগুলি কী কী?

সি ++ 03 3.9.1 মৌলিক ধরনের
§7

প্রকারের বিল, চর, wchar_t, এবং স্বাক্ষরিত এবং স্বাক্ষরযুক্ত স্বাক্ষর পূর্ণসংখ্যার প্রকারগুলি সম্মিলিতভাবে অবিচ্ছেদ্য প্রকারগুলি বলা হয় .4৩) অবিচ্ছেদ্য প্রকারের সমার্থক শব্দটি পূর্ণসংখ্যার প্রকার।

পাদটীকা:

৪৩) সুতরাং, গণনাগুলি (.2.২) অবিচ্ছেদ্য নয়; তবে, পরিসংখ্যানগুলি ইনট, স্বাক্ষরবিহীন ইনট, লম্বা বা স্বাক্ষরবিহীন দীর্ঘ হিসাবে উন্নীত করা যেতে পারে, ৪.৪-তে বর্ণিত।

কার্যসংক্রান্ত:

আপনি আপনার শ্রেণীর সংজ্ঞাটির মধ্যে একটি অ্যারে শুরু করতে এনাম ট্রিক ব্যবহার করতে পারেন ।

class A 
{
    static const int a = 3;
    enum { arrsize = 2 };

    static const int c[arrsize] = { 1, 2 };

};

স্ট্যান্ডার্ড কেন এটি অনুমতি দেয় না?

বর্জন এটিকে যথাযথভাবে এখানে ব্যাখ্যা করেছেন :

একটি শ্রেণি সাধারণত একটি শিরোনাম ফাইলে ঘোষিত হয় এবং একটি শিরোনাম ফাইল সাধারণত অনেক অনুবাদ ইউনিটে অন্তর্ভুক্ত থাকে। তবে জটিল লিঙ্কারের নিয়মগুলি এড়ানোর জন্য, সি ++ এর প্রয়োজন প্রতিটি বস্তুর একটি অনন্য সংজ্ঞা রয়েছে। এই নিয়মটি ভঙ্গ হবে যদি সি ++ সত্তাগুলির শ্রেণীর সংজ্ঞা দেয় যা অবজেক্ট হিসাবে মেমোরিতে সঞ্চয় করা দরকার।

কেন কেবলমাত্র static constঅবিচ্ছেদ্য প্রকার এবং এনামগুলিকে শ্রেণীর সূচনা করার অনুমতি দেওয়া হচ্ছে?

উত্তরটি লুকিয়ে আছে বার্জারের উক্তিটি খুব কাছ থেকে পড়তে হবে,
"সি ++ এর প্রয়োজন প্রতিটি বস্তুর একটি অনন্য সংজ্ঞা রয়েছে That এই নিয়মটি যদি ভেঙে দেওয়া হত যদি সি ++ সত্তা শ্রেণীর সংজ্ঞা দেবে যা বস্তু হিসাবে স্মৃতিতে সংরক্ষণ করতে হয়" "

মনে রাখবেন যে কেবল static constপূর্ণসংখ্যাগুলি সংকলনের সময় ধ্রুবক হিসাবে বিবেচনা করা যেতে পারে। সংকলকটি জানে যে পূর্ণসংখ্যার মান যে কোনও সময় পরিবর্তিত হবে না এবং তাই এটি নিজস্ব যাদু প্রয়োগ করতে পারে এবং অপ্টিমাইজেশান প্রয়োগ করতে পারে, সংকলকটি এই জাতীয় শ্রেণীর সদস্যদের কেবল ইনলাইন করে অর্থাৎ এগুলি আর মেমরিতে সংরক্ষণ করা হয় না, যেহেতু স্মৃতিতে সংরক্ষণের প্রয়োজনীয়তা অপসারণ করা হয় , এটি যেমন ভেরিয়েবলগুলি বর্ণন দ্বারা বর্ণিত ব্যতিক্রমকে ব্যতিক্রম দেয়।

এখানে লক্ষণীয় যে এখানে static constঅবিচ্ছেদ্য মানগুলিতে ইন-ক্লাস ইনিশিয়ালেশন থাকতে পারে এমন ধরণের ভেরিয়েবলের ঠিকানা গ্রহণের অনুমতি নেই। স্থিতিশীল সদস্যের ঠিকানা নেওয়া যেতে পারে (এবং কেবলমাত্র যদি) এটির শ্রেণীর বাইরে সংজ্ঞা থাকে his এটি উপরের যুক্তিটিকে আরও বৈধতা দেয়।

এনামগুলিকে এটি অনুমোদিত হয় কারণ একটি গণিত প্রকারের মানগুলি ব্যবহার করা যেতে পারে যেখানে ইনটগুলি আশা করা হয়। উপরে উদ্ধৃতি দেখুন


সি ++ 11 এ কীভাবে এই পরিবর্তন হয়?

সি ++ 11 নির্দিষ্ট পরিমাণে সীমাবদ্ধতা শিথিল করে।

সি ++ 11 9.4.2 স্ট্যাটিক ডাটা সদস্যদের
§3

যদি কোনও স্ট্যাটিক ডেটা সদস্য কনস্টাল আক্ষরিক ধরণের হয়, শ্রেণীর সংজ্ঞাতে এর ঘোষণাটি একটি ব্রেস-বা-সমমান-ইনিশিয়ালাইজার নির্দিষ্ট করতে পারে যেখানে প্রতিটি সূচনা-ধারাটি একটি অ্যাসাইনমেন্ট-এক্সপ্রেশন হয় একটি ধ্রুবক অভিব্যক্তি। আক্ষরিক ধরণের একটি স্ট্যাটিক ডেটা সদস্য constexpr specifier;যদি শ্রেণীর সংজ্ঞায় এটির সাথে ঘোষণা করা যায় তবে এর ঘোষণায় একটি ব্রেস-বা-সম-ইনিশিয়ালাইজার নির্দিষ্ট করা হবে যাতে প্রতিটি সূচনা-ধারাটি একটি অ্যাসাইনমেন্ট-এক্সপ্রেশনএকটি ধ্রুবক প্রকাশ। [দ্রষ্টব্য: এই উভয় ক্ষেত্রেই সদস্য স্থির মত প্রকাশের জন্য উপস্থিত হতে পারে। Noteend নোট] সদস্য যদি প্রোগ্রামে ব্যবহৃত হয় এবং নামপথের স্কোপ সংজ্ঞাটিতে কোনও আরম্ভকারী উপস্থিত না থাকে তবে সদস্যটির নাম স্পেস স্কোপে সংজ্ঞায়িত করা হবে।

এছাড়াও, সি ++ 11 হবে অনুমতি (§12.6.2.8) একটি অ স্ট্যাটিক ডাটা সদস্য যেখানে এটি ঘোষিত হয় সক্রিয়া করা (তার ক্লাসে)। এর অর্থ অনেক সহজ ব্যবহারকারী শব্দার্থক।

নোট করুন যে এই বৈশিষ্ট্যগুলি সর্বশেষতম জিসিসি ৪.7 এ এখনও প্রয়োগ করা হয়নি, সুতরাং আপনি এখনও সংকলনের ত্রুটি পেতে পারেন।


7
সি ++ 11 এ জিনিসগুলি আলাদা। উত্তর আপডেট ব্যবহার করতে পারে।
bames53

4
এটি সত্য বলে মনে হচ্ছে না: "নোট করুন যে কেবল স্থিতিশীল কনস্টের পূর্ণসংখ্যাগুলি সংকলনের সময় ধ্রুবক হিসাবে বিবেচনা করা যেতে পারে The সংকলকটি জানে যে পূর্ণসংখ্যার মান যে কোনও সময় পরিবর্তিত হবে না এবং তাই এটি নিজস্ব যাদু প্রয়োগ করতে পারে এবং অপ্টিমাইজেশন প্রয়োগ করতে পারে, সহজ সংকলক এ জাতীয় শ্রেণীর সদস্যদের ইনলাইন করে অর্থাত্, এগুলি আর মেমরিতে সঞ্চয় করা হয় না , " আপনি কি নিশ্চিত যে তারা প্রয়োজনীয়ভাবে স্মৃতিতে সঞ্চয় না করে? আমি যদি সদস্যদের জন্য সংজ্ঞা প্রদান করি? কি &memberফিরে আসবে?
নওয়াজ

2
@ এলস: হ্যাঁ এটাই আমার প্রশ্ন। তবে কেন সি ++ কেবলমাত্র অবিচ্ছেদ্য প্রকারের জন্য শ্রেণিকক্ষে প্রারম্ভিককরণের অনুমতি দেয়, আপনার উত্তর দ্বারা সঠিক উত্তর দেওয়া হয় না। কেন এটি static const char*সদস্যের জন্য আরম্ভের অনুমতি দেয় না ?
নওয়াজ

3
@ নাওয়াজ: যেহেতু সি ++ 03 কেবল স্ট্যাটিক এবং কনস্ট ইন্টিগ্রাল এবং কনস্ট এনুমারেশন টাইপের জন্য ধ্রুবক- আরম্ভকারী এবং অন্য কোনও ধরণের জন্য অনুমোদিত নয়, সি ++ 11 এটিকে একটি কনস্টেন্ট আক্ষরিক প্রকারে প্রসারিত করে যা ইন-ক্লাস ইনিশিয়েশনের নিয়মকে শিথিল করে। সি ++ তে সম্ভবত একটি তদারকি ছিল যা পরিবর্তনের জন্য সতর্কতা অবলম্বন করেছিল এবং তাই সি ++ 11 এ সংশোধন করা হয়েছিল, যদি পরিবর্তনের কোনও traditionalতিহ্যগত কৌশলগত কারণ থাকে তবে আমি তাদের সম্পর্কে অবগত নই you যদি আপনি কোনও অবদান সম্পর্কে অবগত হন তবে ভাগ করে নিতে পারেন তাদের।
অলোক সেভ

4
আপনার উল্লিখিত "ওয়ার্কআরাউন্ড" সমষ্টি জি ++ নিয়ে কাজ করছে না
iammilind

4

এটি সাধারণ লঙ্কারগুলির পুরানো দিনগুলির একটি প্রত্যয় বলে মনে হয়। আপনি স্থির পদ্ধতিতে স্ট্যাটিক ভেরিয়েবলগুলি কাজ হিসাবে ব্যবহার করতে পারেন:

// header.hxx
#include <vector>

class Class {
public:
    static std::vector<int> & replacement_for_initialized_static_non_const_variable() {
        static std::vector<int> Static {42, 0, 1900, 1998};
        return Static;
    }
};

int compilation_unit_a();

এবং

// compilation_unit_a.cxx
#include "header.hxx"

int compilation_unit_a() {  
    return Class::replacement_for_initialized_static_non_const_variable()[1]++;
}

এবং

// main.cxx
#include "header.hxx"

#include <iostream>

int main() {
    std::cout
    << compilation_unit_a()
    << Class::replacement_for_initialized_static_non_const_variable()[1]++
    << compilation_unit_a()
    << Class::replacement_for_initialized_static_non_const_variable()[1]++
    << std::endl;
}

বিল্ড:

g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx 
g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o

সঞ্চালন করুন:

./main

সত্য যে এই কাজ করে (ধারাবাহিকভাবে, এমনকি বর্গ সংজ্ঞা বিভিন্ন সংকলন ইউনিট অন্তর্ভুক্ত করা হয়), দেখায় যে লিঙ্কার আজ (জিসিসি 4.9.2) আসলে যথেষ্ট স্মার্ট।

মজাদার: 0123বাহুতে এবং 3210x86 এ মুদ্রণ ।


1

আমি মনে করি এটি আপনাকে ঘোষণা এবং সংজ্ঞা মিশ্রণ থেকে বিরত করবে। (আপনি যদি একাধিক জায়গায় ফাইলটি অন্তর্ভুক্ত করেন তবে যে সমস্যাগুলি ঘটতে পারে সেগুলি সম্পর্কে ভাবুন))


0

এটি কারণ A::aযে সমস্ত অনুবাদ ইউনিট ব্যবহার করে তার কেবলমাত্র একটি সংজ্ঞা থাকতে পারে।

আপনি যদি static int a = 3;সমস্ত অনুবাদ ইউনিট অন্তর্ভুক্ত শিরোনামে একটি শ্রেণিতে অভিনয় করে থাকেন তবে আপনি একাধিক সংজ্ঞা পাবেন। অতএব, স্ট্যাটিকের অ-অফ-লাইন সংজ্ঞা জোর করে একটি সংকলক ত্রুটি করে।

এটি ব্যবহার static inlineবা static constপ্রতিকার। static inlineএটি অনুবাদ ইউনিটে ব্যবহৃত হয় এবং প্রতীকটিকে কেবলমাত্র সম্মতি জানায় এবং লিঙ্কার কেবল কমপিট গ্রুপে থাকার কারণে এটি একাধিক অনুবাদ ইউনিটে সংজ্ঞায়িত হলে কেবল একটি অনুলিপি নির্বাচন করে এবং ছেড়ে দেয় ures constফাইল স্কোপে সংকলকটি কখনই প্রতীক নির্গত করে না কারণ এটি সর্বদা কোডে অবিলম্বে প্রতিস্থাপিত হয় যদি না externব্যবহার করা হয়, যা কোনও শ্রেণিতে অনুমোদিত নয়।

নোটটিতে এক জিনিস static inline int b;যেহেতু একটি সংজ্ঞা হিসাবে গণ্য হবে static const int bবা static const A b;এখনও একটি ঘোষণা হিসাবে গণ্য করা হয় এবং আউট-অফ-লাইন নির্ধারণ করা আবশ্যক যদি আপনি এটি বর্গ ভিতরে সংজ্ঞায়িত না। মজার বিষয়টিকে static constexpr A b;একটি সংজ্ঞা হিসাবে ধরা হয়, যেখানে static constexpr int b;ত্রুটি রয়েছে এবং অবশ্যই একটি প্রাথমিক হওয়া উচিত (এটি কারণ তারা এখন সংজ্ঞা হয়ে ওঠে এবং ফাইল স্কোপে কোনও কনস্ট / কনটেক্সটপ্রিফ সংজ্ঞা মতো, তাদের একটি ইনিশিয়ালাইজারের প্রয়োজন হয় যা কোনও অন্তর্নিহিত থাকে না তবে শ্রেণীর ধরণের হয় কারণ এটি = A()একটি সংজ্ঞা যখন এটি একটি অন্তর্ভুক্ত আছে - ঝনঝন এটি অনুমতি দেয় কিন্তু gcc আপনি স্পষ্টভাবে সূচনা করা প্রয়োজন বা এটি একটি ত্রুটি। পরিবর্তে এটি ইনলাইন নিয়ে কোনও সমস্যা নয়)। static const A b = A();মঞ্জুরিপ্রাপ্ত নয় এবং হওয়া আবশ্যক constexprঅথবাinlineক্লাস টাইপ সহ একটি স্ট্যাটিক অবজেক্টের জন্য ইনিশিয়ালারের অনুমতি দেওয়ার জন্য যেমন ক্লাস টাইপের স্ট্যাটিক সদস্যকে ঘোষণার চেয়ে বেশি করে তোলা। সুতরাং হ্যাঁ কিছু পরিস্থিতিতে A a;স্পষ্টভাবে সূচনা করার মতো নয় A a = A();(পূর্বেরটি একটি ঘোষণাপত্র হতে পারে তবে কেবলমাত্র সেই ধরণের জন্য যদি কেবল কোনও ঘোষণার অনুমতি দেওয়া হয় তবে পরবর্তীটি একটি ত্রুটি The দ্বিতীয়টি কেবলমাত্র একটি সংজ্ঞাতে ব্যবহৃত হতে পারে constexprit এটি একটি সংজ্ঞা দেয় makes )। আপনি যদি constexprডিফল্ট কনস্ট্রাক্টর ব্যবহার এবং নির্দিষ্ট করে থাকেন তবে কনস্ট্রাক্টর হওয়া দরকারconstexpr

#include<iostream>

struct A
{
    int b =2;
    mutable int c = 3; //if this member is included in the class then const A will have a full .data symbol emitted for it on -O0 and so will B because it contains A.
    static const int a = 3;
};

struct B {
    A b;
    static constexpr A c; //needs to be constexpr or inline and doesn't emit a symbol for A a mutable member on any optimisation level
};

const A a;
const B b;

int main()
{
    std::cout << a.b << b.b.b;
    return 0;
}

একটি স্ট্যাটিক সদস্য হ'ল একটি স্পষ্ট ফাইল স্কোপ ডিক্লেয়ারেশন extern int A::a;(যা কেবল শ্রেণিতে তৈরি করা যায় এবং লাইন সংজ্ঞার বাইরে একটি শ্রেণীর স্থির সদস্যের অবশ্যই উল্লেখ করা আবশ্যক এবং সংজ্ঞা থাকতে হবে এবং বহিরাগত থাকতে পারে না) যেখানে অ স্থির সদস্যের অংশ কোনও শ্রেণীর সম্পূর্ণ টাইপ সংজ্ঞা এবং ফাইল স্কোপ ডিক্লেয়ারেশন ব্যতীত একই নিয়ম রয়েছে extern। তারা সুস্পষ্ট সংজ্ঞা। সুতরাং int i[]; int i[5];একটি redefinition যেহেতু হয় static int i[]; int A::i[5];না কিন্তু আছে 2 externs মতো কম্পাইলার এখনও একটি ডুপ্লিকেট সদস্য নির্ণয় করতে পারবে হয় যদি আপনি না static int i[]; static int i[5];ক্লাসে।


-3

স্ট্যাটিক ভেরিয়েবলগুলি একটি শ্রেণীর জন্য নির্দিষ্ট। কনস্ট্রাক্টররা একটি উদাহরণের জন্য ESPECIALY বৈশিষ্ট্যগুলি আরম্ভ করেন।

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