PDA

View Full Version : سوال: ساخت شی از میان کلاس ها



Desaghi
یک شنبه 11 مهر 1395, 22:20 عصر
فرض کنید تعداد زیادی کلاس مختلف دارید. مثلا انواع حیوانات یا هرچیز دیگه
حالا کاربر قرار هست یکی از این کلاسها (نام حیوان) را انتخاب کند و در برنامه می خواهیم بر آن اساس یک شی بسازیم.

چطور می توان بدون دستورات if یا switch این کار را انجام داد؟

در حال حاضر در برنامه مثلا 100 تا if , elseif دارم برای هر کلاس یک elseif که به نظر جالب نیست. راه دیگری می شناسید؟

علی بهمنی جلالی
یک شنبه 11 مهر 1395, 23:21 عصر
سلام
مثلاً می‌توانید بگید اگر نویسه اول رشته شما برابر با a یا A بود، وارد یک تابعی بشه که آن تابع کار پردازش رشته‌هایی که با a یا A شروع می‌شن را برعهده بگیره. اینطوری کد کمتری درون تابع اصلی خودتون می‌نویسید.

T.R.G.T
دوشنبه 12 مهر 1395, 01:50 صبح
یک مشخصه خاص برای هر کلاس اتخاب کنید و با استفاده از اون مشخصه فراخونی کنید یعنی کلاس A با مشخصه alfa و رابط کاربری b با استفاده از مشخصه alfa با هم ارتباط داشته باشن که برای اینکار میتونید از چندید روش استفاده کنید ولی بهترین گزینه که اگه بتونید درست پیاده کنید میتونید در هر نقطه نرم افزار ازش استفاده کنید استفاده از یک سیستم رویداد.

حامد مصافی
سه شنبه 13 مهر 1395, 19:23 عصر
در بعضی از کتابخانه‌ها مانند Qt می‌تونید با استفاده از نام کلاس (در یک متغیر رشته‌ای) نسخه‌ای از اونو ایجاد کنید. آیا از کتابخانه خاصی استفاده می‌کنید؟

one hacker alone
چهارشنبه 14 مهر 1395, 05:11 صبح
تو سی# شما با action ها میتونید تابعی رو فراخوانی کنید که اسمش توی مثلا تکست باکس هست اما تو سی++ نمیدونم اینجوری دقیقا اون چیزی که کاربر وارد میکنه میشه تابعی که باید فراخوانی بشه دیگه نیاز به شرط های پشت سر هم نیست

Ananas
پنج شنبه 15 مهر 1395, 11:13 صبح
فرض کنید یک کلاس پایه دارید به این شکل:

class Base
{
};

و یک سری کلاس ازش مشتق شدن:

class A: public Base
{
};

class B: public Base
{
};

class C: public Base
{
};

class D: public Base
{
};

حالا به ازای هر کلاس یک تابع تعریف میکنیم بیرون کلاس که یک نسخه از اون کلاس برامون بسازه. برای این کار من مکرو تعریف میکنم که کد نویسیش کمتر شه و همشون قالب یکسان داشته باشن:

#define CreateNewFn_MACRO(type_name) \
Base * CreateNew_##type_name() \
{ \
return new type_name(); \
};

CreateNewFn_MACRO(A);
CreateNewFn_MACRO(B);
CreateNewFn_MACRO(C);
CreateNewFn_MACRO(D);

حالا یک نوع از اشاره گر به این توابع تعریف میکنیم و یک آرایه از اشاره گر به تابع که شامل تمام کلاس ها بشه:

typedef Base * (p_fn_newclass)();
p_fn_newclass * vec_fn[] =
{
CreateNew_A,
CreateNew_B,
CreateNew_C,
CreateNew_D
};


حالا خیلی راحت با استفاده از اندیس، هر کلاسیو خاستم میسازم:

Base * x = vec_fn[i]();

T.R.G.T
پنج شنبه 15 مهر 1395, 15:21 عصر
#include <iostream>
#include <string>
#include <map>

using namespace std;


class test0
{
public:
virtual void getName()
{
cout << "\nI'm test0";
}
};

class test1 : public test0
{
public:
void getName()
{
cout << "\nI'm test1";
}
};

class test2 : public test0
{
public:
void getName()
{
cout << "\nI'm test2";
}
};

class test3 : public test0
{
public:
void getName()
{
cout << "\nI'm test3";
msg();
}
void msg()
{
cout << " and as test3 i'm running this show";
}
};


template<class T> T * classGenerator()
{
T * retV=new T;
return retV;
}


int main()
{

map<int, test0*(*)()> classMap;

enum classID
{
test1ID=0,
test2ID=1,
test3ID=2
} id;

classMap[test1ID] = reinterpret_cast<test0*(*)()>(classGenerator<test1>);
classMap[test2ID] = reinterpret_cast<test0*(*)()>(classGenerator<test2>);
classMap[test3ID] = reinterpret_cast<test0*(*)()>(classGenerator<test3>);

id=test2ID;

(classMap[0]())->getName();
(classMap[1]())->getName();
(classMap[2]())->getName();

(classMap[test1ID]())->getName();
(classMap[test2ID]())->getName();
(classMap[test3ID]())->getName();


(classMap[id]())->getName();
getchar();

return 0;
}


البته مشکل این نوع برنامه نویسی اینه که باید همه چیز از داخل کلاس مدیریت بشه و نمیشه متد های کلاس فرزند رو خارج از کلاس فراخوانی کرد برای اینکار باید یک متد برای فراخوانی متد های داخل کلاس ایجاد کنید

Desaghi
جمعه 16 مهر 1395, 20:44 عصر
در بعضی از کتابخانه‌ها مانند Qt می‌تونید با استفاده از نام کلاس (در یک متغیر رشته‌ای) نسخه‌ای از اونو ایجاد کنید. آیا از کتابخانه خاصی استفاده می‌کنید؟

این همونی هست که لازم دارم.(کدام تابع کیوت؟)
چه کتابخانه دیگری این کار را می کند؟

Desaghi
جمعه 16 مهر 1395, 20:48 عصر
در پست 7:
در این خط
map<int, test0*(*)()> classMap

این عبارت
test0*(*)()
چیه؟
اشاره گر به تابع ...؟

T.R.G.T
شنبه 17 مهر 1395, 04:54 صبح
اشاره گر به تابع که داده با نوع اشاره گر به test0 برمیگردونه

حامد مصافی
شنبه 17 مهر 1395, 13:08 عصر
اینو برات نوشتم. در gcc و لینوکس تستش کردم.

#include <iostream>
#include <functional>
#include <map>


using namespace std;


typedef std::function<void *()> Creator;
typedef std::map<std::string, function<void*()>> Creators;
#define REGISTER_CLASS(x) \
static Registrar<x> __temp ## x(#x);
#define CREATE_CLASS(x) \
Registry::create<x*>(#x);
class Registry
{
//static std::map<std::string, Creator>
static Creators _creators;


public:
template<class C>
static void reg(const std::string &className, Creator func)
{
Registry::_creators[className] = func;
cout << "The class " << className << " registered" << endl;
}

template<class C>
static C create(const std::string &className)
{
if(Registry::_creators.find(className) == Registry::_creators.end()){
cout << "The class " << className << " is not registered" << endl;
return 0;
}
return static_cast<C>(Registry::_creators[className]());
}
};
Creators Registry::_creators;
template<typename T>
class Registrar{


public:
Registrar(string className)
{
Registry::reg<T*>(className, []() {return new T;});
}
};




class Base
{
public:
Base(){}
virtual void Print(){
cout << "Base::Print" << endl;
}
};


class DerivedA : public Base
{
public:
void Print(){
cout << "DerivedA::Print" << endl;
}
};
REGISTER_CLASS(DerivedA)
class DerivedB : public Base
{
public:
void Print(){
cout << "DerivedB::Print" << endl;
}
};
REGISTER_CLASS(DerivedB)


int main(int argc, char **argv) {
Base *derivedA = CREATE_CLASS(DerivedA);
derivedA->Print();

Base *derivedB = CREATE_CLASS(DerivedB);
derivedB->Print();


return 0;
}

Desaghi
شنبه 17 مهر 1395, 17:25 عصر
اگر لطف کنید و مزیت کد بالا را با برنامه پست 7 بگید خیلی ممنون میشم.
استفاده از کلاس Registry در مقایسه با map
:متفکر:

حامد مصافی
شنبه 17 مهر 1395, 18:07 عصر
کد قبلی رو کمی تغییر دادم. الان با گرفتم نام کلاس یک آبجکت از اون رو ایجاد می‌کنه.

#include <iostream>
#include <functional>
#include <map>


using namespace std;


typedef std::function<void *()> Creator;
typedef std::map<std::string, function<void*()>> Creators;
#define REGISTER_CLASS(x) \
static Registrar<x> __temp ## x(#x);
#define CREATE_CLASS(x) \
Registry::create(#x);
class Registry
{
//static std::map<std::string, Creator>
static Creators _creators;


public:
static void reg(const std::string &className, Creator func)
{
Registry::_creators[className] = func;
cout << "The class " << className << " registered" << endl;
}

static void* create(const std::string &className)
{
if(Registry::_creators.find(className) == Registry::_creators.end()){
cout << "The class " << className << " is not registered" << endl;
return 0;
}
return Registry::_creators[className]();
}
};
Creators Registry::_creators;
template<typename T>
class Registrar{


public:
Registrar(string className)
{
Registry::reg(className, []() {return new T;});
}
};




class Base
{
public:
Base(){}
virtual void Print(){
cout << "Base::Print" << endl;
}
};


class DerivedA : public Base
{
public:
void Print(){
cout << "DerivedA::Print" << endl;
}
};
REGISTER_CLASS(DerivedA)
class DerivedB : public Base
{
public:
void Print(){
cout << "DerivedB::Print" << endl;
}
};
REGISTER_CLASS(DerivedB)


int main(int argc, char **argv) {
Base *derivedA = static_cast<Base*>(Registry::create("DerivedA"));
derivedA->Print();

Base *derivedB = static_cast<Base*>(Registry::create("DerivedB"));
derivedB->Print();


return 0;
}

T.R.G.T
شنبه 17 مهر 1395, 19:59 عصر
در کل هدف این کد ها یک راهنمایی به شماست در c و c++ شما امکان فراخوانی هیچ نوع ساختار داده ای یا کنترلی به وسیله string یا... رو ندارید و باید ساختار کنترلی خاصی برای اینکار ایجاد کنید که البته در بهترین حالت هم انعطاف پذیری کد شما رو کاهش میده در تمامی کد های نمونه بالا که اساتید زحمتش رو براتون کشیدن ساختار های کنترلی جهت کنترل ایجاد اشیاء مشاهده میکنید اما باید توجه داشته باشید که این روش کد نویسی نیاز به توجه بسیاز زیاد داره چون که فقط مسئله سینتکس نیست بلکه این مشکلات ساختاریه که در این روش برنامه نویسی کار رو سخت میکنه باید مراقب حافظه دینامیک،تبدیل اشیا،و... باشید.
توصیه من به شما اینه که:
_1 یک استاندارد برای ایجاد ، برقراری ارتباط با اشیاء ، و در نهایت حذف اشیاء ایجاد کنید و با این استاندارد در سراسر کد با اشیاء رفتار کنید.
_2 یک کلاس برای ایجاد،حذف،نگهداری و کنترل تمامی اشیاء ایجاد کنید تا مدیریت حافظه براتون راحت تر بشه.
_3 معمولا هر کلاس دارای متد های خاص خودشه در این روش دسترسی به متد هایی که داخل کلاس مادر و جود ندارند ممکن نیست مگر اینکه داخل کلاس فرزند این متد ها را مدیریت کنید مثلا اگه بخواید متد B رو از داخل کلاس فرزند فراخوانی کنید یک رشته به متد A (متد اوراید شده از کلاس مادر) میفرستید با مقدار "a" و برای آرگومان های متد B هم میتونید رشته رو همراه یک آرایه به متد A ارسال کنید داخل متد A بایک سوئیچ ساده میتونید متد B اجرا و جوابش رو برگردونیدبا اینکار میتونید کنترل متد های داخل کلاس فرزند رو به اختیار بگیرید.
_4 باز دوباره تاکید میکنم مدیریت حافظه مهم ترین نکته در این روشه.