বেসরকারী কনস্ট্রাক্টর কখন প্রাইভেট কনস্ট্রাক্টর হয় না?


92

ধরা যাক আমার একটি টাইপ আছে এবং আমি এর ডিফল্ট কনস্ট্রাক্টরকে ব্যক্তিগত করতে চাই। আমি নিম্নলিখিত লিখছি:

class C {
    C() = default;
};

int main() {
    C c;           // error: C::C() is private within this context (g++)
                   // error: calling a private constructor of class 'C' (clang++)
                   // error C2248: 'C::C' cannot access private member declared in class 'C' (MSVC)
    auto c2 = C(); // error: as above
}

দুর্দান্ত

তবে তারপরে, নির্মাণকারীটি ব্যক্তিগত হিসাবে ততটা ব্যক্তিগত হিসাবে দেখা যাচ্ছে না যা আমি ভেবেছিলাম:

class C {
    C() = default;
};

int main() {
    C c{};         // OK on all compilers
    auto c2 = C{}; // OK on all compilers
}    

এটি আমাকে খুব আশ্চর্যজনক, অপ্রত্যাশিত এবং স্পষ্টতই অনাকাঙ্ক্ষিত আচরণ হিসাবে আঘাত করে। কেন এই ঠিক আছে?


25
C c{};সামগ্রিক সূচনা কি কোনও নির্মাণকারীকে বলা হয় না?
নাথান অলিভার

4
@ নাথান অলিভার যা বলেছে আপনার কোনও ব্যবহারকারীর দ্বারা সরবরাহ করা কনস্ট্রাক্টর নেই, সুতরাং Cসামগ্রিক।
কেরেক এসবি

4
@ কেরেকএসবি একই সাথে, আমার কাছে অবাক করে দিয়েছিল যে ব্যবহারকারী সুস্পষ্টভাবে কোনও সিটার ঘোষণা করে যে কর্টরটিকে ব্যবহারকারী সরবরাহ করে না।
অ্যাঞ্জিউ

4
@ অ্যাঞ্জিউ যে কারণে আমরা সবাই এখানে আছি :)
ব্যারি

4
@ অ্যাঞ্জিউ যদি এটি একটি সরকারী কর্তা হয় তবে এটি =defaultআরও যুক্তিসঙ্গত বলে মনে হবে। তবে ব্যক্তিগত =defaultকর্টরটি একটি গুরুত্বপূর্ণ বিষয় বলে মনে হচ্ছে যা এড়ানো উচিত নয়। এর চেয়ে বড় কথা, class C { C(); } inline C::C()=default;কিছুটা অবাক করাও।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

উত্তর:


61

ট্রিকটি সি ++ ১৪ 8.4.2 / 5 [dcl.fct.def.default] এ রয়েছে:

... একটি ফাংশন ব্যবহারকারী-প্রদত্ত যদি এটি ব্যবহারকারী-ঘোষিত হয় এবং তার প্রথম ঘোষণায় স্পষ্টতই খেলাপি বা মুছে ফেলা হয় না। ...

যার মানে C'র ডিফল্ট কন্সট্রাকটর আসলে না , ব্যবহারকারী-প্রদান করা হয়েছে কারণ এটি স্পষ্টভাবে তার প্রথম ঘোষণা উপর ডিফল্ট করা হয়। যেমন, Cকোনও ব্যবহারকারীর দ্বারা সরবরাহিত কনস্ট্রাক্টর নেই এবং অতএব প্রতি 8.5.1 / 1 এর সমষ্টি [dcl.init.aggr]:

একটি সমষ্টি হ'ল একটি অ্যারে বা একটি ক্লাস (ক্লজ 9) যার সাথে কোনও ব্যবহারকারী সরবরাহিত কনস্ট্রাক্টর (12.1) নেই, কোনও ব্যক্তিগত বা সুরক্ষিত নন-স্ট্যাটিক ডেটা সদস্য নয় (ক্লজ 11), কোনও বেস ক্লাস (ক্লজ 10) এবং ভার্চুয়াল ফাংশন নেই (10.3 )।


13
কার্যত, একটি ছোট স্ট্যান্ডার্ড ত্রুটি: এই প্রসঙ্গে ডিফল্ট কর্টর ব্যক্তিগত ছিল তা কার্যকরভাবে উপেক্ষিত।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

4
@ ইয়াক্ক আমি এটি বিচার করার যোগ্য মনে করি না। যদিও কর্টরটি ব্যবহারকারী দ্বারা সরবরাহ করা হচ্ছে না সে সম্পর্কে শব্দটি খুব ইচ্ছাকৃত দেখাচ্ছে।
অ্যাঞ্জু আর এসও

4
@ ইয়াক্ক: আচ্ছা, হ্যাঁ এবং না। ক্লাসে যদি কোনও ডেটা সদস্য থাকত তবে তাদের ব্যক্তিগত করার সুযোগ পেতাম। ডেটা সদস্যবিহীন, খুব কম পরিস্থিতি রয়েছে যেখানে এই পরিস্থিতি মারাত্মকভাবে কাউকে প্রভাবিত করবে।
কেরেক এসবি

4
@ কেরেকএসবি এটি বিবেচনা করে যদি আপনি ক্লাসটি "অ্যাক্সেস টোকেন" ধরণের ব্যবহার করে চেষ্টা করেন, তবে উদাহরণস্বরূপ, কে ক্লাসের কোনও অবজেক্ট তৈরি করতে পারে তার উপর ভিত্তি করে ফাংশনটি কল করতে পারে।
অ্যাঞ্জু আর

4
@ ইয়াক্ক আরও আকর্ষণীয় হ'ল C{}এটি কনস্ট্রাক্টর deleteডি থাকলেও কাজ করে ।
ব্যারি

56

আপনি ডিফল্ট কনস্ট্রাক্টরকে কল দিচ্ছেন না, আপনি একটি সামগ্রিক প্রকারে সমষ্টিগত সূচনা ব্যবহার করছেন। সমষ্টিগত ধরণের একটি ডিফল্ট নির্মাতা থাকার অনুমতি দেওয়া হয়, যতক্ষণ না এটি যেখানে প্রথম ঘোষণা করা হয়েছে সেখানে খেলাপি হয়েছে:

থেকে [dcl.init.aggr] / 1 :

একটি সমষ্টি হ'ল একটি অ্যারে বা একটি শ্রেণি (ক্লজ [ক্লাস]) সহ

  • কোনও ব্যবহারকারী-সরবরাহকারী কনস্ট্রাক্টর ([শ্রেণি.ক্টর]) (একটি বেস বর্গ থেকে উত্তরাধিকারসূত্রে ([नेमস্পেস.উডেস্কেল]) সহ),
  • কোনও ব্যক্তিগত বা সুরক্ষিত অ-স্থিতিশীল ডেটা সদস্য নেই (ক্লজ [শ্রেণি.অ্যাক্সেস]),
  • কোনও ভার্চুয়াল ফাংশন ([শ্রেণি। ভার্চুয়াল]), এবং
  • ভার্চুয়াল, প্রাইভেট, বা সুরক্ষিত বেস ক্লাস নেই ([class.mi])।

এবং [dcl.fct.def.default] / 5 থেকে

সুস্পষ্টভাবে ডিফল্ট ফাংশন এবং সুস্পষ্টভাবে ঘোষিত ফাংশনগুলিকে সম্মিলিতভাবে ডিফল্ট ফাংশন বলা হয় এবং বাস্তবায়ন তাদের ([class.ctor] [class.dtor], [class.copy]) জন্য অন্তর্নিহিত সংজ্ঞা প্রদান করে, যার অর্থ তাদের মুছে ফেলা হিসাবে সংজ্ঞায়িত করা হতে পারে । কোনও ফাংশনটি ব্যবহারকারী-সরবরাহিত হয় যদি এটি ব্যবহারকারী-ঘোষিত হয় এবং তার প্রথম ঘোষণায় স্পষ্টতই খেলাপি বা মুছে ফেলা হয় না। একটি ব্যবহারকারী দ্বারা সরবরাহিত স্পষ্টতই-খেলাপী কার্য (যেমন, তার প্রথম ঘোষণার পরে স্পষ্টতই খেলাপি হয়) এমন স্থানে সংজ্ঞায়িত হয় যেখানে এটি স্পষ্টতই খেলাপি হয়; যদি এই জাতীয় কোনও ফাংশন স্পষ্টভাবে মুছে ফেলা হিসাবে সংজ্ঞায়িত করা হয় তবে প্রোগ্রামটি নিরবচ্ছিন্ন।[দ্রষ্টব্য: কোনও ক্রিয়াকলাপটিকে তার প্রথম ঘোষণার পরে খেলাপি হিসাবে ঘোষিত করা একটি কার্যকর কোড বেসে স্থিতিশীল বাইনারি ইন্টারফেস সক্ষম করার সময় কার্যকর কার্যকরকরণ এবং সংক্ষিপ্ত সংজ্ঞা প্রদান করতে পারে। - শেষ নোট]

সুতরাং, সামগ্রিকের জন্য আমাদের প্রয়োজনীয়তাগুলি হ'ল:

  • কোনও জনসাধারণের সদস্য নেই
  • কোন ভার্চুয়াল ফাংশন
  • ভার্চুয়াল বা অ-পাবলিক বেস ক্লাস নেই
  • কোনও ব্যবহারকারীর দ্বারা সরবরাহিত কনস্ট্রাক্টররা উত্তরাধিকারসূত্রে বা অন্যথায় নয়, যা কেবলমাত্র নির্মাণকারীদেরই অনুমতি দেয়:
    • সুস্পষ্টভাবে ঘোষিত, বা
    • স্পষ্টভাবে ঘোষণা এবং একই সময়ে খেলাপী হিসাবে সংজ্ঞায়িত।

C এই সমস্ত প্রয়োজনীয়তা পূরণ করে।

স্বাভাবিকভাবেই, আপনি খালি ডিফল্ট কনস্ট্রাক্টর সরবরাহ করে বা নির্মাতাকে এটির ঘোষণার পরে ডিফল্ট হিসাবে সংজ্ঞায়িত করে এই ভুয়া ডিফল্ট নির্মাণ আচরণ থেকে মুক্তি পেতে পারেন:

class C {
    C(){}
};
// --or--
class C {
    C();
};
inline C::C() = default;

4
অ্যাঞ্জের চেয়ে এই উত্তরটি আমার চেয়ে কিছুটা ভাল লেগেছে, তবে আমি মনে করি এটি বেশিরভাগ দুটি বাক্যে শুরুতে সংক্ষিপ্তসার থেকে উপকৃত হবে।
পিজেট্রাইল

7

অ্যাঞ্জু এবং জ্যাজডস্পায়ারের উত্তরগুলি দুর্দান্ত এবং এতে প্রযোজ্য। এবং। এবং

তবে, ইন , জিনিসগুলি কিছুটা বদলে যায় এবং ওপিতে উদাহরণটি আর সংকলন করে না:

class C {
    C() = default;
};

C p;          // always error
auto q = C(); // always error
C r{};        // ok on C++11 thru C++17, error on C++20
auto s = C{}; // ok on C++11 thru C++17, error on C++20

দুটি উত্তরের দ্বারা নির্দেশিত হিসাবে, দ্বিতীয় দুটি ঘোষণাপত্রের কাজটি কারণ Cএকটি সমষ্টি এবং এটি সামগ্রিক-সূচনা। যাইহোক, পি 1008 এর ফলাফল হিসাবে (ওপি থেকে খুব আলাদা নয় এমন একটি অনুপ্রেরণামূলক উদাহরণ ব্যবহার করে), [dcl.init.aggr] / 1 থেকে সি ++ 20 তে সামগ্রিক পরিবর্তনের সংজ্ঞা :

সমষ্টিগত হ'ল একটি অ্যারে বা একটি শ্রেণি ([শ্রেণী])

  • কোনও ব্যবহারকারী-ঘোষিত বা উত্তরাধিকারসূতী নির্মাণকারী ([শ্রেণি.কমর]),
  • কোনও ব্যক্তিগত বা সুরক্ষিত সরাসরি অ-স্থিতিশীল ডেটা সদস্য নয় ([শ্রেণী.অ্যাক্সেস]),
  • কোনও ভার্চুয়াল ফাংশন ([শ্রেণি। ভার্চুয়াল]), এবং
  • ভার্চুয়াল, প্রাইভেট, বা সুরক্ষিত বেস ক্লাস নেই ([class.mi])।

জোর আমার। এখন প্রয়োজনীয়তা কোনও ব্যবহারকারী-ঘোষিত কনস্ট্রাক্টর নয়, যেখানে এটি ব্যবহৃত হত (উভয় ব্যবহারকারী তাদের উত্তরে উদ্ধৃত করেছেন এবং সি ++ 11 , সি ++ 14 , এবং সি ++ 17 এর জন্য historতিহাসিকভাবে দেখা যেতে পারে ) কোনও ব্যবহারকারী-সরবরাহকারী কনস্ট্রাক্টর নেই । এর জন্য ডিফল্ট কনস্ট্রাক্টরটি Cব্যবহারকারী-ঘোষিত, তবে ব্যবহারকারীর দ্বারা সরবরাহিত নয়, এবং তাই C ++ 20 এ সমষ্টি হতে পারে।


এখানে সামগ্রিক পরিবর্তনের আরেকটি উদাহরণস্বরূপ উদাহরণ রয়েছে:

class A { protected: A() { }; };
struct B : A { B() = default; };
auto x = B{};

Bসি ++ 11 বা সি ++ 14 এ মোট সমষ্টি ছিল না কারণ এটির একটি বেস শ্রেণি রয়েছে। ফলস্বরূপ, B{}কেবলমাত্র ডিফল্ট কনস্ট্রাক্টরকে (ব্যবহারকারী দ্বারা ঘোষিত তবে ব্যবহারকারী দ্বারা সরবরাহিত নয়) অনুরোধ জানানো হয়েছে, যার Aসুরক্ষিত ডিফল্ট কনস্ট্রাক্টরের অ্যাক্সেস রয়েছে ।

সি ++ 17 তে, P0017 এর ফলাফল হিসাবে , বেস ক্লাসগুলির অনুমতি দেওয়ার জন্য সমষ্টিগুলি বাড়ানো হয়েছিল। Bসি ++ 17 এ একটি সমষ্টি, যার অর্থ B{}হ'ল সমষ্টিগত-ইনিশিয়ালাইজেশন যা সাবোবজেক্ট সহ সমস্ত সাবওজেক্টগুলি আরম্ভ করতে হয় A। তবে Aএর ডিফল্ট কনস্ট্রাক্টর সুরক্ষিত থাকার কারণে আমাদের এতে অ্যাক্সেস নেই, তাই এই সূচনাটি দুর্গঠিত।

সি ++ ২০-এ, Bব্যবহারকারী দ্বারা B{}নির্ধারিত কনস্ট্রাক্টরের কারণে এটি আবার সমষ্টি হিসাবে বন্ধ হয়ে যায়, তাই এটি ডিফল্ট কনস্ট্রাক্টরকে অনুরোধ করতে ফিরে আসে এবং এটি আবার সু-গঠিত সূচনা হয়।

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