رفتن به مطلب
مرجع رسمی سی‌پلاس‌پلاس ایران
  • 1
قاسم رمضانی منش

استفاده از template class در فایل جداگانه


سوال

ارسال شده در (ویرایش شده)

سلام 

در صورتی که تعاریف توابع عضو کلاس (class function member definition) را در همان فایل anothertest.h قرار دهیم برنامه بدون مشکلی اجرا میشود. اما در صورتی که تعاریف توابع را به داخل فایل anothertest.cpp انتقال دهیم ، برنامه کامپایل ولی با خطای لینکر مواجه میشود. 

دلیل این اتفاق چیست ؟

--ویرایش : پس از جستجویی که انجام دادم متوجه شدم که به دلیل اینکه کامپایلر برای هر نمونه از template هایی که ما نیاز داریم یک نسخه جداگانه درست میکند. مثلا در کد زیر. کد باید به این صورت تغییر کند :

class TemplateTest{
  private :
    int ClassVariable;
  public :
    TemplateTest(const int& input);
    int ReturnClassVariable(void);
};

 

Git Diff

 #ifndef ANOTHERTEST_H
 #define ANOTHERTEST_H
 
-template <class AnotherType>
 class TemplateTest{
   private :
-    AnotherType ClassVariable;
+    int ClassVariable;
   public :
-    TemplateTest(const AnotherType& input);
-    AnotherType ReturnClassVariable(void);
+    TemplateTest(const int& input);
+    int ReturnClassVariable(void);
 };
 
 #endif // ANOTHERTEST_H

و از آنجایی که تعاریف کلاس ها در فایل دیگری قرار دارد. کامپایلر فراموش به نمونه سازی از آنها میکند. و به این دلیل است که با خطای لینکر مواجه میشویم. و برای رفع این مشکل باید تعاریف توابع را نیز در فایل anothertest.h قرار بدهیم. 

با این اوصاف آیا روش دیگه ای هست که  از template ها در فایل های جداگانه استفاده کنیم ؟

anothertest.h

#ifndef ANOTHERTEST_H
#define ANOTHERTEST_H

template <class AnotherType>
class TemplateTest{
  private :
    AnotherType ClassVariable;
  public :
    TemplateTest(const AnotherType& input);
    AnotherType ReturnClassVariable(void);
};

#endif // ANOTHERTEST_H

 

anothertest.cpp

#include "anothertest.h"

template<class AnotherType>
TemplateTest<AnotherType>::TemplateTest(const AnotherType &input) :
  ClassVariable(input){

}

template<class AnotherType>
AnotherType TemplateTest<AnotherType>::ReturnClassVariable(){
  return this->ClassVariable;
}

 

main.cpp

#include <iostream>
#include "anothertest.h"

int main(){
  TemplateTest<int> AnotherTemplate(100);
  std::cout << AnotherTemplate.ReturnClassVariable () << std::endl;
  return 0x0000;
}

 

ویرایش شده در توسط قاسم رمضانی منش

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

3 پاسخ به این سوال تا کنون داده شده است

پست های پیشنهاد شده

  • 2

با توجه به پاسخی که در مورد دلیلش یافتید، در تکمیل روش جنابِ @فرهاد شیری روش‌های مختلفی برای تعاریف کلاس‌ها از نوع template در فایل cpp  وجود دارد که قبل از C++17 روش زیر یکی از روش‌های رایج است که در آن شما کلاس را با انواع صریح تعریف می‌کنید.

کد مربوط به فایل .h به صورت زیر خواهد بود:

#ifndef ENTITY_H
#define ENTITY_H

#include <iostream>
#include <string>

template<class T>
#define ENTITY_INT      template class Entity<int>;
#define ENTITY_STRING   template class Entity<std::string>;
#define ENTITY_BOOL     template class Entity<bool>;
#define ENTITY_DOUBLE   template class Entity<double>;

/*!
 * \brief The Entity class
 */
class Entity
{
public:
    Entity();
    ~Entity();

    /*!
     * \brief Function
     * \param t
     */
    void Function(const T &t) const;

};

#endif // ENTITY_H

همچنین کد مربوط به فایل .cpp به صورت زیر پیاده سازی خواهد شد:

#include "entity.h"

template<class T>
Entity<T>::Entity()
{

}

template<class T>
Entity<T>::~Entity()
{

}

template<typename T>
void Entity<T>::Function(const T &t) const
{
    std::cout << "T = " << t << std::endl;
}

ENTITY_INT
ENTITY_STRING
ENTITY_BOOL
ENTITY_DOUBLE

روش استفاده:

#include <iostream>
#include "entity.h"


int main(void)
{

    Entity<int> *en = new Entity<int>;
    en->Function(10);
    delete en;

    Entity<double> *en2 = new Entity<double>;
    en2->Function(2000.23);
    delete en2;

    Entity<std::string> *en3 = new Entity<std::string>;
    en3->Function("Hello, World!");
    delete en3;

}

نکته: در استاندارد ۱۷ استفاده از پارامتر‌های auto نیز برای بهینه نویسی بیشتر مفید هستند.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0

سلام

در  لینک اول کلا این سوال شما رو توضیح داده و گفته چرا این اتفاق میفته و در مورد سوال دومتون هم سه روش رو گفته که میتونید یکی رو انتخاب کنید

How to define a template class in a .h file and implement it in a .cpp file - CodeProject

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0

@Amir Balazadeh  دوست عزیز ! مرسی از پاسخِتان. ولی بهتر بود که توضیح میدادید موارد را به جای اینکه لینک ارسال کنید :).

 

روش حل این مشکل را با توجه به روش هایی که داخل ساتی CodeProject گفته شده بود میگم تا ذخیره ای برای بقیه دوستانی باشد که این سوال رو دارن.

داخل لینک سه روش گفته شده بود که دو روش رُ اینجا میگم :

به همان دلیلی که گفتم 

در 4 ساعت قبل، قاسم رمضانی منش گفته است :

دلیل اینکه کامپایلر برای هر نمونه از template هایی که ما نیاز داریم یک نسخه جداگانه درست میکند.

+ و کامپایل متوجه تعریفاتی که در فایل anothertest.cpp کردیم نمیشوند. برای رفع این مشکل ما باید یا تعاریف توابع خودمان را داخل خود کلاس قرار بدیم. یا اینکه خارج از کلاس ولی در همان فایلی که کلاس در آن هست. یعنی فایل anthertest.h. خب ! اینجا میتونیم از قابلیت های پیش‌پردازنده در سی‌پلاس‌پلاس استفاده کنیم. 

قبل از اینکه روش حل مشکل را بگم. یه نگاه به روش کار کرد این خط از کد بکنیم :

File1.h

void AnotherFunction(void){
  std::cout << "I Can't do Anything :(" << std::endl;
}

main.cpp

#include "file1.h"

int main(){
  return 0;
}

خب برای اینکه خروجی این فایل را مشاهده کنیم و متوجه بشیم که چطوری پیش‌پردازندهٔ #include کار میکند. با استفاده از این دستور و کامپایلر gcc برنامه را کامپایل میکنیم :

[ghasem@clibcore an]$ g++ -E main.cpp > file

و حالا خروجی حاصل از دستور بالا :

[ghasem@clibcore an]$ cat file
# 1 "main.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.cpp"
# 1 "file1.h" 1
void AnotherFunction(void){
  std::cout << "I Can't do Anything :(" << std::endl;
}
# 2 "main.cpp" 2
int main(){
    return 0;
}

امیدوارم کار پیش‌پردازندهٔ #include را قشنگ متوجه شده باشید :).

 

حالا برای قسمت حل مشکل template ها !.

یه راه ساده برای حل این مشکل اینکه ما با فایل anothertest.cpp را بعد از کلاس با استفاده از #include اضافه کنیم ... به اینصورت :

class TemplateTest{
  private :
    int ClassVariable;
  public :
    TemplateTest(const int& input);
    int ReturnClassVariable(void);
};
#include "anothertest.cpp"

و یک راه دیگه : هر دوفایل anothertest.cpp و anothertest.h را داخل فایل کدمان یعنی main.cpp وارد کنیم :

#include <iostream>
#include "anothertest.h"
#include "anothertest.cpp"
 
int main(){
  TemplateTest<int> AnotherTemplate(100);
  std::cout << AnotherTemplate.ReturnClassVariable () << std::endl;
  return 0x0000;
}

 

با تشکر.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

به گفتگو ملحق شوید

شما همین الآن می‌توانید مطلبی را ارسال و بعداً ثبت‌نام کنید. اگر حساب کاربری دارید، و با حساب کاربری خود مطلب ارسال کنید.
نکته: مطلب شما قبل از انتشار نیاز به بازبینی توسط میانجی‌گر‌ها دارد.

مهمان
پاسخ به این سوال ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


  • کاربران آنلاین در این صفحه   0 کاربر

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

×
×
  • جدید...