ورود

View Full Version : یک تجربه: تمپلیتها در فایلهای هدر



Sepidar
جمعه 13 مهر 1386, 10:37 صبح
این مورد من رو خیلی اذیت کرد، می نویسم تا ایشالا نفر بعدی به این مشکل نخوره:
قضیه خیلی سادست: تو gcc اگه یه کلاس تمپلت تو یه فایل هدر تعریف کردی، پیاده سازیش هم دقیقه باید تو همون فایل هدر باشه، یعنی اگه مثلا تعریفش تو myHeader.h بود، پیاده سازیش هم باید تو myHeader.h باشه و نه توی مثلا myHeader.cpp
http://forums.codeblocks.org/index.php/topic,2051.0.html

emad_67
جمعه 13 مهر 1386, 11:28 صبح
کلا فکر میکنم تو همه نسخه های c++ هم به این شکل باشه (البته شک دارم) ولی توی visual که من کار میکنم هم به همین شکله. البته توی کتابی هم که من میخوندم اومده بود و واسطه کلاس رو از پیاده سازیش جدا کرده بود که اون موقع بنده هم هر چی سر و کله زدم توفیقی نکرد. تا بعدا فهمیدم که نباید جداشون کرد. ضمنا فکر میکنم این مورد برای همه کلاس ها صدق میکنه نه فقط کلاس های تمپلیت (توی visual که اینجوریه)

sh_roohani
جمعه 13 مهر 1386, 16:56 عصر
سلام عرض شد،

به عرضتون برسونم تا اونجایی که بنده اطلاع دارم (و قبلا هم فکر می کنم توی همین انجمن در این مورد بحث شده)، هنوز هیچ کامپایلر ++Cی این قابلیت رو پیاده سازی نکرده که prototype کلاس های مبتنی بر template رو از implementation اونا جدا کنیم. یه نفر که یادم نیست کی بود بهم گفت که این کار از نظر فنی طراحی کامپایلر رو خیلی پیچیده می کنه. بنابراین شما باید prototype و implementation کلاس های templateی رو یا در فایل h و یا در فایل cpp با هم بیارید و نه جدا از هم در دو فایل. این رو هم با GCC و هم با کامپایلر ++C محیط Visual studio 2005 (و البته قبلی هاش) تست کردم.

emad_67
جمعه 13 مهر 1386, 17:30 عصر
سلام
کلا این چیزی که میگین برای همه کلاس ها صادق هست نه فقط کلاس های مبتنی بر template

Sepidar
جمعه 13 مهر 1386, 18:44 عصر
سلام
کلا این چیزی که میگین برای همه کلاس ها صادق هست نه فقط کلاس های مبتنی بر template
wrong



try google before posting dumb answers ;)

emad_67
جمعه 13 مهر 1386, 19:57 عصر
wrong
try google before posting dumb answers ;)
من این چیزی رو که میگم امتحان کردم. یعنی بدنه کلاسی رو که نوشتم در یک فایل .h قرار دادم و بعد این فایل رو include کردم در یک فایل cpp و توابع عضو کلاس رو توی فایل cpp پیاده سازی کردم که با ارور مواجه میشه.

sh_roohani
شنبه 14 مهر 1386, 01:31 صبح
آخه emad_67 جان، چیزی رو که شما امتحان کردین و به خطا برخوردین، من نزدیک به سیزده ساله که دارم کار می کنم و به مشکلی بر نخوردم. شاید اشکال از چیز دیگه ای بوده. اگه همون سورس رو دقیقا اینجا بذارین می شه بررسی کرد که اشکال از کجا بوده.

SMRAH1
شنبه 14 مهر 1386, 01:41 صبح
من هم تا حالا به مشکل بر نخوردم.شاید فایل پیاده سازی کلاس رو به پروژه اضفه نکردین؟

emad_67
شنبه 14 مهر 1386, 09:21 صبح
ببنید من یه مثال کوچیک نوشتم حالا شما بگید اشکالش کجاست
من این کد رو توی فایل "Print.h" قرار دادم


class Print
{
public:
void PrintString();
};

توابع عضو کلاس رو در فایل "Print.cpp" قرار دادم.


#include"Print.h"
#include<iostream.h>
void Print::PrintString()
{
cout<<"Visual c++";
}

و بعد تابع main رو در یک فایل cpp دیگه به این صوزت نوشتم


#include"Print.h"
void main()
{
Print obj;
obj.PrintString();
}



من هم تا حالا به مشکل بر نخوردم.شاید فایل پیاده سازی کلاس رو به پروژه اضفه نکردین؟

طبق نظر جناب SMRAH1 من فایل print.cpp رو به برنامه include کردم و این بار مشکلی پیش نیومد ولی آیا این کار لازمه؟ چون توی این به اصطلاح کتابی که بنده خوندم نوشته که با include کردن print.h خود برنامه با print.cpp کامپایل و پیوند زده میشه

SMRAH1
یک شنبه 15 مهر 1386, 02:19 صبح
حتما باید فایل cpp به پروزه اضافه شود.در واقع فایل هدر معرفی تابع رو تعریف می کنه و فایل cpp تعریف نهایی تابع است و مهم هم نیست که اسمش چیه (مثلا در مثال بالا شاید فایل Print.cpp را شما به اسم دیگه ای مثل A.cpp قرار داده باشید).کامپایلر در موقع لینک کردن تعریف دقیق تابع رو (توی هر فایل obj که باشد) پیدا کرده و به برنامه اصلی لینک می کند.البته اگر چند تا تعریف نهایی پیدا کنه یا تعریف نهایی تابعی رو پیدا نکند، پیغام حطای لینک می دهد.
در ضمن از این همه غلط نوشتن (حروف را کم یا یا زیاد می نویسم) معذرت می خواهم.(;

emad_67
یک شنبه 15 مهر 1386, 08:08 صبح
با تشکر
خوب با این اوصاف که شما می فرمایید حرف جناب Sepidar هم اشتباه میشه چون اگه ازهمین روش برای کلاس های مبتنی بر template استفاده کنیم هیچ مشکلی پیش نمیاد.

sh_roohani
یک شنبه 15 مهر 1386, 09:00 صبح
سلام،

ببینید emad_67 عزیز، این دو تا مسئله به هم بی ارتباط هستن. مهم اینه که پیاده سازی فایل رو کامپایلر پیدا کنه و از اون کد باینری بسازه تا زمان لینک بتونه لینکر ازش استفاده کنه. حالا فایلش cpp باشه یا C یا cxx یا h یا hpp خیلی مهم نیست. این تقسیم بندیها بیشتر برای انسانه تا برای کامپایلر. اما در مورد template ها prototype و implementation حتما باید در یه فایل باشه. مسئله به همین سادگیه.

emad_67
یک شنبه 15 مهر 1386, 09:42 صبح
خوب اگه شما هم قبول دارین که باید فایل cpp رو به برنامه اضافه کرد دیگه برای template ها هم این موضوع فرقی نمیکنه چون من به همین صورت برای template ها امتحان کردم و مشکلی پیش نیومد به طور مثال اینو ببینید
این بدنه کلاس در فایل num.h :


template<class T>
class Number
{
public:
Number(T);
T GetNumber();
private:
T num;
};

این کد پیاده سازی توی فایل num.cpp :


#include"num.h"
template<class T>
Number<T>::Number(T x)
{
num=x;
}
template<class T>
T Number<T>::GetNumber()
{
return num;
}

اینم کد تابع main در فایل cpp دیگه


#include<iostream.h>
#include"num.cpp"
void main()
{
Number<float> obj(2.5);
cout<<obj.GetNumber();
}

من این برنامه رو اجرا کردم و مشکلی پیش نیومد
البته شرمنده که سرتون رو درد اوردم
با تشکر

sh_roohani
یک شنبه 15 مهر 1386, 11:23 صبح
سلام دوباره،

ببینید منظور از اون بحث اضافه کردن فایل پیاده سازی به پروژه س. علت هم اینه که تا وقتی به پروژه اضافه نکنیدش، کامپایلر اونو کامپایل نمی کنه و در نتیجه لینکر به اشکال بر می خوره. اما در مورد این کدی که شما اینجا گذاشتین، شما عملا تمام interface و implementation کلاس رو یه جا تعریف کردین (در فایل main). اگه می خواین ببینین اشکال چطوری پیش میاد، به جای num.h فایل num.cpp رو توی فایل اصلی include کنید. من اینو همین الان هم تو محیط Code::Blocks با کامپایلر mingw نسخه 3.4.2 آزمایش کردم.

emad_67
یک شنبه 15 مهر 1386, 11:34 صبح
یا سلام و تشکر از جوابتون


ببینید منظور از اون بحث اضافه کردن فایل پیاده سازی به پروژه س. علت هم اینه که تا وقتی به پروژه اضافه نکنیدش، کامپایلر اونو کامپایل نمی کنه و در نتیجه لینکر به اشکال بر می خوره. اما در مورد این کدی که شما اینجا گذاشتین، شما عملا تمام interface و implementation کلاس رو یه جا تعریف کردین (در فایل main).

درسته عملا به همین شکل میشه. پس حرفی که جناب Sepidar در پست اول گفتن یعنی چی؟ منظورشون این بوده که فقط فایل num.h رو در فایل main اضافه کنم؟


اگه می خواین ببینین اشکال چطوری پیش میاد، به جای num.h فایل num.cpp رو توی فایل اصلی include کنید.

خوب الان هم فایل num.cpp توی فایلی که تابع main قرار داره include شده.

sh_roohani
یک شنبه 15 مهر 1386, 11:42 صبح
آقا من معذرت می خوام، حواسم نبود، برعکس نوشتم. به جای num.cpp فایل num.h رو include کنین.

در ضمن، این جملات رو عینا از کتاب C++ How to Program نسخه 5 ژانویه 2005 نقل می کنم:

Most C++ compilers require the complete definition of a template to appear in the client source-code file that uses the template. For this reason and for reusability, templates are often defined in header files, which are then #included into the appropriate client source-code files. For class templates, this means that the member functions are also defined in the header file.








اما در مورد فرمایش جناب سپیدار، با تصحیح سوتی که من در پست قبلی دادم، حرف ایشون هم درست میاد. یعنی در واقع حرف ایشون درست بود، من تو پست قبلیم اشتباه کردم.

emad_67
یک شنبه 15 مهر 1386, 11:55 صبح
آقا من معذرت می خوام، حواسم نبود، برعکس نوشتم. به جای num.cpp فایل num.h رو include کنین.

خوب اگه num.h رو include کنم ارور میده. حق با شماست ولی این ارور حتی برای کلاس های معمولی هم پیش میاد. در پست صفحه قبل هم یه مثالی گذاشتم که ارور پیش میومد ولی گفتن که باید فایل .cpp رو هم که حاوی پیاده سازی کلاس هست اضافه کنم.
به هر حال اگه فایل .cpp رو اضافه کنم که به قول خودتون مثل این میشه که کل کلاس و توابع اونو در فایل main تعریف کردم. اگه اضافه نکنم هم طبیعی هست که ارور پیش میاد. البته نه فقط برای کلاس های template بلکه برای همه کلاس ها.
الان این پست بنده رو شما ببینید و بگید که مشکلش چیه که ارور میده( یک کلاس معمولی هم هست که به قول شما نباید ارور بده)
http://barnamenevis.org/forum/showpost.php?p=404469&postcount=9
با تشکر

sh_roohani
یک شنبه 15 مهر 1386, 12:08 عصر
نه برادر، اون اضافه کردن منظور include کردن نیست، منظور اضافه کردن به پروژه داخل workspace تونه. پروژه یه تعریف ساختاریه مربوط به محیطی که توش کار می کنید که به درد Project Manager می خوره واسه اینکه بدونه کدوم فایلها رو باید کامپایل کنه و بده به لینکر. مثلا اگه شما target و rule لازم برای کامپایل کردن یه فایل cpp رو توی makefile نیارین، اما بخواین object code اونو به بقیه برنامه تون لینک کنین، خوب بدیهیه که به اشکال لینک بر می خورین، نه اشکال کامپایل. ولی اگه اون target و rule رو توی makefile قید کنین، به این می گن اضافه کردن به پروژه. حالا IDE ها معمولا makefile رو به اون معنی که ما با کامپایلرهای خط دستوری می شناسیم نمی سازن، به جاش هرکدوم یه جور فایل پروژه برای خودشون می سازن که کم و بیش همون کار makefile رو می کنه و تقریبا به همه IDE ها هم می شه گفت که makefile هم تولید کنن.
به این ترتیب اضافه کردن یه فایل به ساختار پروژه با include کردن یه فایل توی یه فایل دیگه فرق داره.

حالا شما اگه دقیقا پیغامهای خطایی رو که توی همون مثال مورد اشاره تون می گیرین اینجا بذارین باز می شه مسئله رو روشن تر توضیح داد. منظورم اینه که شما احتمالا خطای لینک می گیرین (تو مورد کلاسهای غیر templateی رو عرض می کنم) نه خطای کامپایل.

emad_67
یک شنبه 15 مهر 1386, 12:22 عصر
بازم خیلی ممنون دست عزیز
در هر دو مورد کامپایل ارور نداره و همون ارور link رو میده در واقع پیاده سازی تابع رو پیدا نمیکنه مثلا ارور هایی که در کلاس template بالا میده (با اضافه کردن num.h ) به این شکله:


error LNK2001: unresolved external symbol "public: float __thiscall Number<float>::GetNumber(void)" (?GetNumber@?$Number@M@@QAEMXZ)
error LNK2001: unresolved external symbol "public: __thiscall Number<float>::Number<float>(float)" (??0?$Number@M@@QAE@M@Z)

ارور هایی که برای اون کلاس معمولی هم میده مثل همینه
البته من با vs 2000 کار میکنم و اصلا برای فایلم project نمیسازم یعنی مثل 2005 نیست حتما بخواد project تعریف کنی. حالا من چه جوری باید مشکل رو رفع کنم. البته بنده هم از کتاب دیتل خوندم ولی هیچ وقت نتونستم به شکلی که گفته بود فایل رو اجرا کنم

sh_roohani
یک شنبه 15 مهر 1386, 12:43 عصر
راستش من نمی دونم این vs 2000 چیه، اما علت گرفتن این خطاهای لینک همینه که پروژه نمی سازین و در نتیجه ارتباط بین فایلها برای لینکر مشخص نیست. بنابراین تنها راهتون اینه که مستقیما فایل cpp رو include کنین. در واقع چه تو فایل پروژه و چه تو makefile شما ارتباط بین فایلها و نحوه کامپایل و لینک رو برای tool chain خودتون مشخص می کنین.

emad_67
یک شنبه 15 مهر 1386, 12:49 عصر
به هر حال خیلی ممنون از جواباتون و از اینکه وقتتون رو هم گرفتم شرمنده

Anti_Evil
یک شنبه 15 مهر 1386, 13:32 عصر
همه ی کامپایلرها اجازه پیاده سازی Template هارو در فایل جداگانه نمی دهند .

ویژوال سی هم به طور کامل پشتیبانی نمی کنه ..

sh_roohani
یک شنبه 15 مهر 1386, 13:57 عصر
به هر حال خیلی ممنون از جواباتون و از اینکه وقتتون رو هم گرفتم شرمنده

خواهش می کنم. ولی لطفا اگه مسئله هنوز براتون حل نشده بگین. چون این گیر به نظر من خیلی اساسیه.

emad_67
یک شنبه 15 مهر 1386, 16:45 عصر
خواهش می کنم. ولی لطفا اگه مسئله هنوز براتون حل نشده بگین. چون این گیر به نظر من خیلی اساسیه.

نه دوست عزیز تا همین جا هم که پیگیری کردی خیلی خیلی ممنونم. من یک پروژه ساختم و همه اینا رو توی اون امتحان کردم و همه چیز رو متوجه شدم. البته قبلا اصلا پروژه نمی ساختم و مستقیما یک فایل cpp ایجاد میکردم که همین هم مشکل ساز میشد.
با تشکر فراوان
موفق باشید

Sepidar
یک شنبه 13 شهریور 1390, 15:08 عصر
نمونه سازی با تاخیر در C++‎0x (http://melmi.ir/blog/?p=81)