অবজেক্ট ওরিয়েন্টেড সি লেখা কি খারাপ? [বন্ধ]


14

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

struct foo {
    int x;
};

struct foo* createFoo(); // mallocs foo

void destroyFoo(struct foo* foo); // frees foo and its things

এটা কি খারাপ অভ্যাস? আমি কীভাবে সিটিকে "সঠিক উপায়" লিখতে শিখি।


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

13
" [টি] তিনি স্থির করেছিলেন যে রিয়েল প্রোগ্রামার যে কোনও ভাষায় ফরটার প্রোগ্রাম লিখতে পারে " "- এড পোস্ট, 1983
রস প্যাটারসন

4
আপনি সি ++ এ স্যুইচ করতে চান না এমন কোনও কারণ আছে কি? আপনি পছন্দ করেন না এমন অংশগুলি ব্যবহার করতে হবে না use
সুইভ

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

3
@ jpmc26: আপনি যদি ভাষাগত prescriptivist হন, তাহলে আপনি অ্যালান কে শুনতে হবে, তিনি মেয়াদ উদ্ভাবিত তিনি এটা মানে কি বলতে পায়, এবং তিনি বলেছেন গলি মেসেজিং সম্পর্কে সব হয় । আপনি যদি ভাষাগত বর্ণনাকারী হন তবে আপনি সফ্টওয়্যার বিকাশকারী সম্প্রদায়টিতে এই শব্দটির ব্যবহারের সমীক্ষা করবেন। কুক ঠিক সেটাই করেছিলেন, তিনি ভাষাগুলির বৈশিষ্ট্যগুলি বিশ্লেষণ করেছেন যা হয় দাবি করে বা তাকে ওও হিসাবে বিবেচনা করা হয়, এবং তিনি দেখতে পান যে তাদের মধ্যে একটি জিনিস মিল রয়েছে: মেসেজিং
Jörg ডব্লু মিটাগ

উত্তর:


24

না, এটি খারাপ অভ্যাস নয়, এমনকি এটি করার জন্যও উত্সাহিত করা হয়েছে, যদিও কেউ এমনকি সম্মেলনের মতো struct foo *foo_new();এবং ব্যবহার করতে পারেvoid foo_free(struct foo *foo);

অবশ্যই, একটি মন্তব্য যেমন বলেছে, কেবল যেখানে উপযুক্ত সেখানে এটি করুন। একটির জন্য কনস্ট্রাক্টর ব্যবহার করার কোনও ধারণা নেই int

উপসর্গটি foo_অনেকগুলি গ্রন্থাগার অনুসরণ করে একটি সম্মেলন, কারণ এটি অন্যান্য গ্রন্থাগারের নামকরণের সাথে সংঘর্ষ থেকে রক্ষা করে। অন্যান্য ফাংশনগুলিতে প্রায়শই ব্যবহারের জন্য কনভেনশন থাকে foo_<function>(struct foo *foo, <parameters>);। এটি struct fooআপনাকে অস্বচ্ছ ধরণের হতে দেয় ।

কনভেনশনটির জন্য libcurl ডকুমেন্টেশনটি দেখুন , বিশেষত "সাব-নেমস্পেসস" সহ, যাতে curl_multi_*প্রথম প্যারামিটারটি ফিরে আসার সময় কোনও ফাংশন কল করা প্রথম দর্শনে ভুল দেখায় curl_easy_init()

আরও বেশি জেনেরিক পন্থা রয়েছে, এএনএসআই-সি সহ অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং দেখুন


11
সর্বদা সাবধান "যেখানে উপযুক্ত"। ওওপি কোনও রূপালী-বুলেট নয়।
হস্তান্তরকারী

আপনি কি এই ফাংশনগুলি ডিক্লেয়ার করতে পেরে সি এর নামস্থান নেই? অনুরূপ std::string, আপনি না পারে foo::create? আমি সি ব্যবহার করি না এটি কেবল সি ++ তে আছে?
ক্রিস সাইরেফাইস

@ ক্রিসিসায়ারফাইস সি-তে কোনও নেমস্পেস নেই, এ কারণেই অনেক লাইব্রেরি লেখক তাদের কাজগুলির জন্য উপসর্গ ব্যবহার করেন।
রেসিডুম

2

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


4
আমি দ্বিমত করতে পারি না এমন নয়, তবে আপনার মতামতটি কিছুটা ব্যাখ্যা দ্বারা সমর্থিত হওয়া উচিত ।
উত্সাহক

1

এটা খারাপ না. এটি RAII ব্যবহার করার অনুমোদন দেয় যা অনেকগুলি বাগ (মেমরি ফাঁস, অবিচ্ছিন্ন ভেরিয়েবলগুলি ব্যবহার করে, ফ্রি-এর পরে ব্যবহার ইত্যাদি যা সুরক্ষার সমস্যার কারণ হতে পারে) প্রতিরোধ করে।

সুতরাং, আপনি যদি নিজের কোডটি কেবল জিসিসি বা কলঙ্কের সাথে (এবং এমএস সংকলকের সাথে নয়) সংকলন করতে চান তবে আপনি cleanupবৈশিষ্ট্যটি ব্যবহার করতে পারেন , এটি আপনার অবজেক্টগুলিকে সঠিকভাবে ধ্বংস করবে ruct আপনি যদি নিজের বিষয়টিকে এমনভাবে ঘোষণা করেন:

my_str __attribute__((cleanup(my_str_destructor))) ptr;

তারপরে my_str_destructor(ptr)পিটিআর সুযোগের বাইরে চলে গেলে চালানো হবে। কেবল মনে রাখবেন, এটি ফাংশন আর্গুমেন্টের সাথে ব্যবহার করা যাবে না ।

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


2
আফাইক, আরআইআই পরিষ্কারভাবে সুনিশ্চিত করার জন্য সি ++ এর অবজেক্টগুলির জন্য ডেস্ট্রাক্টরদের অন্তর্নিহিত কলিং ব্যবহার করার বিষয়ে স্পষ্টরূপে রিসোর্স রিলিজ কলগুলি যুক্ত করার প্রয়োজন এড়িয়ে চলে। সুতরাং, আমি যদি খুব বেশি ভুল না করি, তবে RAII এবং C পারস্পরিক একচেটিয়া।
কাস্টমস্টার

@ মাস্টার যদি আপনি #defineনিজের টাইপনেমগুলি ব্যবহার করেন __attribute__((cleanup(my_str_destructor)))তবে আপনি এটি পুরো #defineসুযোগে অন্তর্নিহিত হিসাবে পাবেন (এটি আপনার সমস্ত পরিবর্তনশীল ঘোষণায় যুক্ত হবে)।
মার্কিন

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

আমার উত্তরে উল্লিখিত হিসাবে, এটি ঝাঁকুনিতেও কাজ করে।
মার্কিন

আহ, আমি তা খেয়াল করিনি। এটি প্রকৃতপক্ষে প্রয়োজনীয়তাটিকে ক) তাত্পর্যপূর্ণভাবে কম তীব্র করে তোলে, কারণ এটি __attribute__((cleanup()))যথেষ্ট পরিমাণে একটি আধা-মানক করে তোলে । তবে, খ) এবং গ) এখনও দাঁড়িয়ে আছে ...
মাস্টার - মোনিকা

-2

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

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

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

উদাহরণস্বরূপ, traditionalতিহ্যবাহী সংকলকগুলিতে, historicalতিহাসিক সংকলকগুলি নিম্নলিখিত কোডটি ব্যাখ্যা করবেন:

struct pair { int i1,i2; };
struct trio { int i1,i2,i3; };

void hey(struct pair *p, struct trio *t)
{
  p->i1++;
  t->i1^=1;
  p->i1--;
  t->i1^=1;
}

যাতে নিম্নলিখিত পদক্ষেপগুলি যথাযথভাবে সম্পাদন করা হয়: প্রথম সদস্যের বর্ধিতকরণ, প্রথম সদস্যের *pসর্বনিম্ন বিট পরিপূরক *t, তারপরে প্রথম সদস্যের হ্রাস *p, এবং প্রথম সদস্যের সর্বনিম্ন বিট পরিপূরক *t। আধুনিক সংকলকগুলি কোনও ফ্যাশনে ক্রিয়াকলাপগুলি পুনরায় সাজিয়ে তুলবে যা কোন কোডে আরও কার্যকর হবে pএবং tবিভিন্ন বস্তু সনাক্ত করতে পারে তবে তারা যদি তা না করে তবে আচরণটি পরিবর্তন করবে।

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

কিছুটা স্বতন্ত্র প্রকারের কাছে দুটি পয়েন্টার অদলবদলের মতো কিছু করার জন্য কোনও ফাংশন লিখতে চাইলে কিছুটা কম সংঘাতযুক্ত উদাহরণ দেখা দেয়। "1990 এর সি" সংকলকের বিশাল সংখ্যায়, এটি এর মাধ্যমে সম্পন্ন হতে পারে:

void swap_pointers(void **p1, void **p2)
{
  void *temp = *p1;
  *p1 = *p2;
  *p2 = temp;
}

স্ট্যান্ডার্ড সি তে তবে একটি ব্যবহার করতে হবে:

#include "string.h"
#include "stdlib.h"
void swap_pointers2(void **p1, void **p2)
{
  void **temp = malloc(sizeof (void*));
  memcpy(temp, p1, sizeof (void*));
  memcpy(p1, p2, sizeof (void*));
  memcpy(p2, temp, sizeof (void*));
  free(temp);
}

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


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

এইচএম ... মন আপনি কীভাবে দেখান যে মানটি যে গ্যারান্টি দেয় তা আপনাকে সাধারণ প্রাথমিক সাব-সিকোয়েন্সের সদস্যদের পরিষ্কারভাবে অ্যাক্সেস করতে দেয় না? কারণ আমি মনে করি যে এই মুহুর্তে চুক্তিভিত্তিক আচরণের গণ্ডির মধ্যে অপ্টিমাইজ করার সাহসের খারাপগুলি সম্পর্কে আপনার অভিমান কি? (এই দুটি অনুমানকারী আপত্তিজনক বলে মনে করেছিল তা আমার ধারণা।)
উত্সাহককারী

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

@ উত্সাহক: নির্দেশিত উদাহরণটি দেখুন। ক্ষেত্র "i1" উভয় কাঠামোর সাধারণ প্রাথমিক ক্রমের একটি সদস্য, তবে কোড কোনও "স্ট্রাক্ট ট্রায়ো" এর প্রাথমিক সদস্য অ্যাক্সেসের জন্য "স্ট্রাক্ট জোড় *" ব্যবহার করার চেষ্টা করলে আধুনিক সংকলকগুলি ব্যর্থ হবে।
সুপারক্যাট

কোন আধুনিক সি সংকলক উদাহরণটি ব্যর্থ করে? কোন আকর্ষণীয় বিকল্প প্রয়োজন?
উত্সাহক

-3

পরবর্তী পদক্ষেপ হ'ল কাঠামো ঘোষণাটি আড়াল করা। আপনি এটি .h ফাইলে রেখেছেন:

typedef struct foo_s foo_t;

foo_t * foo_new(...);
void foo_destroy(foo_t *foo);
some_type foo_whatever(foo_t *foo, ...);
...

এবং তারপরে .c ফাইলে:

struct foo_s {
    ...
};

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