কেন .c ফাইলে না। # ফাইলে #fndef CLASS_H এবং # ডিফাইন CLASS_H ব্যবহার করবেন?


136

আমি সবসময় মানুষ লিখতে দেখেছি

class.h

#ifndef CLASS_H
#define CLASS_H

//blah blah blah

#endif

প্রশ্নটি হল, তারা ক্লাস ফাংশনগুলির সংজ্ঞা ধারণ করে এমন .cpp ফাইলের জন্য কেন তা করে না?

আসুন বলে রাখি আমার আছে main.cppএবং এর main.cppমধ্যে রয়েছে class.hclass.hফাইল নেই includeকিছু, তাহলে এটা কিভাবে main.cppকি হয় class.cpp?


5
"আমদানি" সম্ভবত আপনি এখানে ব্যবহার করতে চান এমন শব্দ নয়। অন্তর্ভুক্ত করুন।
কেট গ্রেগরি

5
সি ++ এ, ফাইল এবং ক্লাসগুলির মধ্যে 1-থেকে -1 সম্পর্ক নেই। আপনি চাইলে একটি ফাইলে যতগুলি ক্লাস রাখতে পারেন (বা একাধিক ফাইলের মধ্যে একটি শ্রেণিকে বিভক্ত করুন, যদিও এটি খুব কমই সহায়ক)। সুতরাং ম্যাক্রো হওয়া উচিত FILE_H, না CLASS_H
এসবিআই

উত্তর:


302

প্রথমত, আপনার প্রথম তদন্তটি সম্বোধন করার জন্য:

আপনি যখন এটি .h ফাইলে দেখেন :

#ifndef FILE_H
#define FILE_H

/* ... Declarations etc here ... */

#endif

এটি হিডার ফাইলটিকে একাধিকবার অন্তর্ভুক্ত করা থেকে বিরত রাখার একটি প্রাকপ্রসেসর কৌশল, যা বিভিন্ন কারণে সমস্যাযুক্ত হতে পারে। আপনার প্রকল্পের সংকলনের সময়, প্রতিটি .cpp ফাইল (সাধারণত) সংকলিত হয়। সহজ কথায়, এর অর্থ এই যে সংকলকটি আপনার .cpp ফাইল নেবে , এর #includedদ্বারা যে কোনও ফাইল খুলবে , সেগুলি সমস্তকে একটি বৃহত পাঠ্য ফাইলে সংযুক্ত করবে এবং তারপরে সিনট্যাক্স বিশ্লেষণ করবে এবং শেষ পর্যন্ত এটি এটিকে কিছু মধ্যবর্তী কোডে রূপান্তরিত করবে, অপ্টিমাইজ করবে / অন্য সম্পাদন করবে কাজগুলি, এবং শেষ পর্যন্ত লক্ষ্য আর্কিটেকচারের জন্য সমাবেশ আউটপুট উত্পন্ন করে। এই কারণে যদি কোনও ফাইল #includedএক .cpp এর অধীনে একাধিকবার হয়ফাইল, সংকলক দুটিবার এর ফাইলের বিষয়বস্তু সংযোজন করবে, সুতরাং সেই ফাইলের মধ্যে যদি সংজ্ঞা থাকে তবে আপনি একটি ভেরিয়েবলকে নতুন করে সংজ্ঞায়িত করে একটি সংকলক ত্রুটি পাবেন। সংকলন প্রক্রিয়ার প্রিপ্রসেসর ধাপ দ্বারা ফাইলটি প্রক্রিয়া করা হয়, প্রথমবার যখন এর বিষয়বস্তু প্রথম দুটি লাইনে পৌঁছায় FILE_Hতখন প্রিপ্রোসেসরের জন্য সংজ্ঞায়িত করা হয়েছে কিনা তা পরীক্ষা করবে । যদি তা না হয় তবে FILE_Hএটি কোডটি #endifনির্দেশ এবং নির্দেশকের মধ্যে সংজ্ঞায়িত করে প্রক্রিয়া চালিয়ে যাবে । পরের বার যখন ফাইলের বিষয়বস্তু প্রিপ্রোসেসর দ্বারা দেখা যাবে, তার বিরুদ্ধে চেকটি FILE_Hমিথ্যা হবে, সুতরাং এটি তাত্ক্ষণিকভাবে স্ক্যান করে #endifএটির পরে চালিয়ে যাবে। এটি পুনরায় সংজ্ঞা ত্রুটিগুলি প্রতিরোধ করে।

এবং আপনার দ্বিতীয় উদ্বেগের সমাধান করতে:

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

এই বাহ্যিকগুলি কীভাবে সমাধান করা হয় তা লিঙ্কারের জন্য কাজ। আপনার কম্পাইলার প্রক্রিয়া যখন main.cpp , এটা ঘোষণা কোড পায় class.cpp অন্তর্ভুক্ত করে class.h । কেবলমাত্র এই ফাংশনগুলি বা ভেরিয়েবলগুলি দেখতে কেমন তা জানতে হবে (এটি কোনও ঘোষণা আপনাকে দেয়)। সুতরাং এটি আপনার মেইন.পি.পি ফাইলটিকে কিছু বস্তুর ফাইলের মধ্যে সংকলন করে (এটিকে মেইন.ওবিজে কল করুন )। একইভাবে, Class.cpp একটি class.obj তে সংকলিত হয়ফাইল। চূড়ান্ত নির্বাহযোগ্য উত্পাদন করতে, একটি লিঙ্কার সেই দুটি অবজেক্ট ফাইল একসাথে লিঙ্ক করতে অনুরোধ করা হয়। যে কোনও অমীমাংসিত বহিরাগত ভেরিয়েবল বা ফাংশনগুলির জন্য, সংকলকটি একটি স্টাব স্থাপন করবে যেখানে অ্যাক্সেস ঘটে। লিঙ্কারটি তখন এই স্টাবটি নেবে এবং অন্য তালিকাভুক্ত অবজেক্ট ফাইলে কোড বা ভেরিয়েবলের সন্ধান করবে এবং যদি এটি খুঁজে পাওয়া যায় তবে এটি দুটি অবজেক্ট ফাইল থেকে কোডটিকে একটি আউটপুট ফাইলে সংযুক্ত করে এবং স্টাবটিকে ফাংশনের চূড়ান্ত অবস্থানের সাথে প্রতিস্থাপন করে বা পরিবর্তনশীল। এই ভাবে, main.cpp আপনার কোডে ফাংশন এবং ব্যবহারের ভেরিয়েবল কল করতে পারেন class.cpp যদি এবং কেবল যদি তারা ঘোষণা করা class.h

আশা করি এটা উপকারে এসেছিল।


আমি কয়েকদিন ধরে .h এবং .cpp বোঝার চেষ্টা করছিলাম। এই উত্তরটি আমার সময় এবং সি ++ শিখার আগ্রহটি সঞ্চয় করেছিল। ভালভাবে লিখিত. ধন্যবাদ জাস্টিন!
রাজকুমার আর

আপনি সত্যিই দুর্দান্ত ব্যাখ্যা করেছেন! উত্তরগুলি চিত্রগুলির সাথে থাকলে সম্ভবত বেশ ভাল হবে
আলামিন

13

CLASS_Hএকটি হল পাহারা অন্তর্ভুক্ত ; এটি একই সিপিপি ফাইলের (বা আরও সঠিকভাবে একই অনুবাদ ইউনিট ) একাধিকবার (বিভিন্ন রুটের মাধ্যমে) একই হেডার ফাইলটি অন্তর্ভুক্ত করা এড়ানোর জন্য ব্যবহৃত হয় যা একাধিক সংজ্ঞা ত্রুটির দিকে পরিচালিত করে।

সিপিপি ফাইলগুলিতে অন্তর্ভুক্ত রক্ষীদের প্রয়োজন হয় না কারণ সংজ্ঞা অনুসারে, সিপিপি ফাইলের বিষয়বস্তু কেবল একবারই পড়ে।

মনে হয় আপনি অন্তর্ভুক্ত রক্ষীদের importঅন্যান্য ভাষায় বিবৃতি হিসাবে (যেমন জাভা) একই কাজ করে ; যাইহোক, এটি ক্ষেত্রে নয়। #includeনিজেই মোটামুটিভাবে সমতূল্য importঅন্যান্য ভাষায়।


2
"একই সিপিপি ফাইলের মধ্যে" একই অনুবাদ ইউনিটের মধ্যে "পড়া উচিত"।
ড্রিমলাক্স

@ ড্রিমলাক্স: ভাল কথা - আমি এটিই মূলত লিখতে যাচ্ছিলাম, তবে আমি বুঝতে পেরেছিলাম যে যে কেউ প্রহরীকে বুঝতে পারে না সে কেবল "অনুবাদ ইউনিট" শব্দটি দ্বারা বিভ্রান্ত হতে চলেছে। আমি প্রথম বন্ধনে "অনুবাদ ইউনিট" যুক্ত করতে উত্তরটি সম্পাদনা করব - এটি উভয় বিশ্বের সেরা হওয়া উচিত।
মার্টিন বি

6

এটি না - কমপক্ষে সংকলনের পর্যায়ে রয়েছে।

উত্স কোড থেকে মেশিন কোডে সি ++ প্রোগ্রামের অনুবাদটি তিনটি পর্যায়ে সম্পাদিত হয়:

  1. প্রাক প্রসেসিং - প্রিপ্রসেসর # এর সাথে শুরু হওয়া লাইনের জন্য সমস্ত উত্স কোডকে বিশ্লেষণ করে এবং নির্দেশগুলি কার্যকর করে। আপনার ক্ষেত্রে, আপনার ফাইলের বিষয়বস্তুগুলি class.hলাইনের জায়গায় inোকানো হয়েছে #include "class.h। যেহেতু আপনি আপনার হেডার ফাইলটি বেশ কয়েকটি স্থানে অন্তর্ভুক্ত থাকতে পারেন, তাই #ifndefঅনুচ্ছেদগুলি সদৃশ নির্দেশটি কেবল প্রথমবার অন্তর্ভুক্ত করার পরে প্রিপ্রসেসর নির্দেশিকা অনির্ধারিত হওয়ায় নকলগুলি সদৃশ ঘোষণা-ত্রুটিগুলি এড়িয়ে চলে।
  2. সংকলন - সংকলক এখন সমস্ত প্রাক-প্রসেসড উত্স কোড ফাইলগুলি বাইনারি অবজেক্ট ফাইলগুলিতে অনুবাদ করে।
  3. সংযোগ স্থাপন - লিঙ্কার লিঙ্কগুলি (সুতরাং নাম) বস্তুর ফাইলগুলি একসাথে। আপনার শ্রেণি বা এর যে কোনও একটি পদ্ধতির একটি রেফারেন্স (যা ক্লাস। এ ঘোষণা করা উচিত এবং ক্লাস। পিপিতে সংজ্ঞায়িত করা উচিত) কোনও অবজেক্ট ফাইলে সংশ্লিষ্ট অফসেটে সমাধান করা হয়েছে। আমি আপনার 'অবজেক্ট ফাইলগুলির একটি লিখি' যেহেতু আপনার ক্লাসটি ক্লাস। সিপি নামের একটি ফাইলে সংজ্ঞায়িত করার প্রয়োজন হয় না , এটি কোনও লাইব্রেরিতে থাকতে পারে যা আপনার প্রকল্পের সাথে যুক্ত।

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


4

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

কিছু ব্যবহার করার জন্য আপনাকে কেবল এটির ঘোষণার সংজ্ঞা নয়, এটি জানতে হবে। কেবল লিঙ্কারের সংজ্ঞাটি জানা দরকার।

সুতরাং এক বা একাধিক উত্স ফাইলের মধ্যে আপনি একটি শিরোনাম ফাইল অন্তর্ভুক্ত করবেন তবে আপনি অন্যের মধ্যে কোনও উত্স ফাইল অন্তর্ভুক্ত করবেন না।

এছাড়াও আপনি বোঝাতে চান #includeএবং আমদানি করেন না।


3

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

উত্স ফাইলের জন্য নিজেই এটি করার দরকার নেই যেহেতু (সাধারণত) যা অন্য কোনও ফাইল দ্বারা অন্তর্ভুক্ত নেই।

আপনার শেষ প্রশ্নের class.hজন্য, শ্রেণীর সংজ্ঞা এবং এর সমস্ত সদস্যের ঘোষণাপত্র, যুক্ত ফাংশন এবং অন্য যে কোনও কিছু থাকা উচিত, যাতে কোনও ফাইল যাতে এতে অন্তর্ভুক্ত থাকে তবে ক্লাসটি ব্যবহার করার পর্যাপ্ত তথ্য থাকতে পারে। ফাংশনগুলির বাস্তবায়ন পৃথক উত্স ফাইলে যেতে পারে; এগুলি কল করার জন্য আপনার কেবল ঘোষণাপত্রের দরকার।


2

main.cpp কি হয় নেই class.cpp । এটা ঠিক ফাংশন / ক্লাস ঘোষণা জানাতে চাই যে, এটি ব্যবহার করার জন্য যায় আছে, এবং এই ঘোষণা হয় class.h

যেখানে ফাংশন / শ্রেণীর ঘোষণা মধ্যে linker সংযোগগুলি class.h ব্যবহার করা হয় এবং তাদের বাস্তবায়নের class.cpp


1

.cppফাইলগুলি #includeঅন্য ফাইলগুলিতে অন্তর্ভুক্ত নয় (ব্যবহার করে )। সুতরাং তাদের রক্ষণাবেক্ষণ অন্তর্ভুক্ত করার দরকার নেই। Main.cppআপনি শ্রেণীর নাম এবং স্বাক্ষরগুলি জানতে পারবেন যা আপনি প্রয়োগ করেছেন class.cppকেবল কারণ আপনি সমস্ত নির্দিষ্ট করেছেন class.h- এটি একটি শিরোনাম ফাইলের উদ্দেশ্য। (এটি আপনি নিশ্চিত করেছেন যে class.hআপনি যে কোডটি প্রয়োগ করেছেন তা সঠিকভাবে বর্ণনা করেছে class.cpp।) এক্সিকিউটেবল কোডটি লিঙ্কারের প্রচেষ্টার জন্য class.cppএক্সিকিউটেবল কোডে উপলব্ধ করা হবে main.cpp


1

সাধারণত প্রত্যাশা করা হয় যে .cppযুক্তির অপ্রয়োজনীয় পুনরাবৃত্তি সংকলন এড়াতে ফাইলগুলির মতো কোডের মডিউলগুলি একবার সংকলিত হয় এবং একাধিক প্রকল্পে লিঙ্কযুক্ত হয়। উদাহরণস্বরূপ, g++ -o class.cppএমন উত্পাদন করবে class.oযা আপনি একাধিক প্রকল্প থেকে ব্যবহারের সাথে লিঙ্ক করতে পারবেন g++ main.cpp class.o

আমরা #includeআমাদের লিঙ্কার হিসাবে ব্যবহার করতে পারি , যেমনটি আপনি বোঝাচ্ছেন বলে মনে হচ্ছে, তবে এটি কেবল নির্বোধ হবে যখন আমরা কী কী কী কম স্ট্রোক এবং আরও অপব্যয়যুক্ত আমাদের কোডের চেয়ে কম কীস্ট্রোক এবং কম বর্জ্য সংকলনের পুনরুক্তি সহ আমাদের সংকলকটি ব্যবহার করে সঠিকভাবে লিঙ্ক করতে জানি that সংকলনের পুনরাবৃত্তি ...

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

এটি উপলব্ধি করা গুরুত্বপূর্ণ যে শিরোনাম ফাইলগুলি সেইগুলি মডিউলগুলির জন্য চিহ্নগুলির সংজ্ঞা সংজ্ঞা দেয়; একবার এটি উপলব্ধি হয়ে গেলে এর পরে বোঝা যায় যে একাধিক অন্তর্ভুক্তি প্রতীকগুলির পুনঃনির্ধারণের কারণ হতে পারে (যা ত্রুটি সৃষ্টি করে), সুতরাং আমরা এই জাতীয় পুনরায় সংজ্ঞা রোধে প্রহরীদের অন্তর্ভুক্ত করি।


0

এটি হেডফায়াইলগুলির কারণে শ্রেণিটি কী রয়েছে তা সংজ্ঞায়িত করে (সদস্য, ডেটা-স্ট্রাকচার) এবং সিপিপি ফাইলগুলি এটি প্রয়োগ করে।

এবং অবশ্যই, এর মূল কারণটি হ'ল আপনি অন্য .h ফাইলগুলিতে এক .h ফাইল একাধিকবার অন্তর্ভুক্ত করতে পারেন, তবে এর ফলে কোনও শ্রেণীর একাধিক সংজ্ঞা হবে, যা অবৈধ।

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