Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > инициализация const в производном классе


Автор: ksili 17.7.2008, 08:41
Проблема такова. Я делаю в Билдере многопоточное приложение. Для этого в нём предусмотрен класс TThread. Все потоки, создаваемые приложением должны быть потомками этого класса. У меня несколько таких потомков. Всё было нормально, пока я не захотел несколько членов этих классов сделать константными т.к. они собственно константами и являются (их значение задаётся в самом начале, и потом не меняется). Сделать это я решил, т.к. в разных местах говорится, что это гуд (см. например, С.Мэйерс "Эффективное использование С++"), но не в этом суть. Сделать-то я их сделал такими, а инициализировать не получается.
Вот как они инициализировались раньше:
Код

TDispatchThread *pdt;
...
pdt = new TDispatchThread (true);    // создали экземпляр класса потока и "заморозили" его
                    
pdt->hCom = port;    // инициализируем его члены
pdt->this_ch = num - 1;
pdt->All_ch = All_chnls;

pdt->Resume();        // "размораживаем" поток

Конструктор, который при этом использовался, выглядит так:
Код

__fastcall TDispatchThread(bool CreateSuspended=true)
    : TThread(CreateSuspended)
{
 this->OnTerminate = (TNotifyEvent)&OnThisTerminate;
 DecimalSeparator = '.';
 InitializeCriticalSection(&g_cs);
}

После того, как я сделал члены класса hCom, this_ch, All_ch константными, так уже делать нельзя, т.к. они инициализируются при вызове конструктора, а не после, как показано выше. Тут, насколько я понял, почитав книжки, нужно использовать конструктор со списком инициализации. Но нигде не нашёл, как это сделать именно для такого случая (конструктор производного класса). Если бы класс не был производным, его конструктор выглядел бы примерно так:
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : hCom(h), this_ch(t), All_ch(a)
{
 this->OnTerminate = (TNotifyEvent)&OnThisTerminate;
 DecimalSeparator = '.';
 InitializeCriticalSection(&g_cs);
}

 А создание объекта примерно так:
Код

pdt = new TDispatchThread (true,port,num-1,All_chnls);

Но из-за того, что там уже есть : TThread(CreateSuspended), я не пойму куда там впихнуть список инициализации. Пробовал так:
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : TThread(CreateSuspended)
    : hCom(h), this_ch(t), All_ch(a)

так
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : hCom(h), this_ch(t), All_ch(a)
    : TThread(CreateSuspended)

так
Код

__fastcall TDispatchThread(bool CreateSuspended, HANDLE h)
    : hCom(h), this_ch(t), All_ch(a), TThread(CreateSuspended)

 и другими подобными способами. Не компилируется. Пишет ошибки { expected и Declaration terminated incorrectly на конструкторе (на этом самом списке инициализации). Кто-нибудь знает, как можно инициализировать константные члены-данные в производном классе?

Автор: Earnest 17.7.2008, 09:03
Так много букв написал, что в этой жаре все подробно прочитать просто никак... smile 
Но если правильно поняла: константу можно инициализировать только в списке инициализации того класса, где она объявлена. А производный класс может только передать желаемый аргумент базовому. Примерно так:
Код

class Base
{
public:
   Base (int A): m_A (A) {}
private:
   const int m_A;
};

class Derived: public Base
{
public:
   Derived(): Base (5) {}
};

Автор: Lazin 17.7.2008, 09:04
Нужно вызывать конструктор базового класса для инициализации членов базового класса
Код


class A
{
    const int a;
    const int b;
    public:
        A(int a, int b) : a(a), b(b) {}
};

class B : public A
{
    public:
        B(int a, int b) : A(a, b)
        {
        }
};

Автор: Earnest 17.7.2008, 09:05
И вообще, прямо инициализировать переменные базового класса в конструкторе производного, даже если это не константы, - плохая идея. Хорошая - сделать их приватными.

Автор: ksili 17.7.2008, 09:06
Earnest, немного не то. Константы и есть в производном классе, в секции public. Я в базовом классе ничего не меняю - он не мой.

Автор: Earnest 17.7.2008, 09:15
Тогда никак. Члена-константы можно инициализировать только в списке инициализации своего конструктора.
Если базовый класс не предусматривает аргументов для альтернативной инициализации своих констант, то вопросы к его автору. Возможно, есть какая-то сермяга.
И если базовый класс не твой, то откуда там взялись константы, которых раньше не было? А константы производного класса инициализуруй на здоровье - в списке инициализации.

Автор: ksili 17.7.2008, 09:21
Цитата(Earnest @  17.7.2008,  13:15 Найти цитируемый пост)
 А константы производного класса инициализуруй на здоровье - в списке инициализации

Дык, вот как раз это и не получается!  smile  Константные члены появились в TDispatchThread, а не в TThread. Я не пойму как совместить в конструкторе производного класса указание списка инициализации hCom(h), this_ch(t), All_ch(a) и указание конструктора базового класса  TThread(CreateSuspended)

Автор: mes 17.7.2008, 09:26
Цитата(ksili @  17.7.2008,  08:41 Найти цитируемый пост)
Но из-за того, что там уже есть : TThread(CreateSuspended), я не пойму куда там впихнуть список инициализации. Пробовал так:
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : TThread(CreateSuspended)
    : hCom(h), this_ch(t), All_ch(a)


вместо второго двоеточия поставь запятую :

Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : TThread(CreateSuspended)
    , hCom(h), this_ch(t), All_ch(a)
{
 ; // остальные действия 
}


Добавлено через 4 минуты и 21 секунду
Цитата(Earnest @  17.7.2008,  09:03 Найти цитируемый пост)
Так много букв написал, 

полностью согласен,
ksili, задавая вопрос постарайся не отходить на дополнительные описания ...трудно понять где именно проблема..  smile 

Автор: Ulysses4j 17.7.2008, 09:44
Не может быть проблемы в несоответствии порядка объявления порядку в листе инициализации? В списке инициализации должны упоминаться сначала базовые классы, потом члены в порядке их объявления в классе. В случае константых членов это важно. В Новых сложных задача Саттера есть совет (14-ый), где он это подробно рассматривает.

Автор: ksili 17.7.2008, 09:52
Цитата(mes @  17.7.2008,  13:26 Найти цитируемый пост)
вместо второго двоеточия поставь запятую :
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h,int t,Channels *a)
    : TThread(CreateSuspended)
    , hCom(h), this_ch(t), All_ch(a)
{
 ; // остальные действия 
}


Я так уже пробовал. При компиляции всё те же ошибки на строке 
Код

 : TThread(CreateSuspended)


Добавлено @ 09:55
Цитата(Ulysses4j @  17.7.2008,  13:44 Найти цитируемый пост)
Не может быть проблемы в несоответствии порядка объявления порядку в листе инициализации?

Я сейчас пробую с одним параметром в инициализации
Код

__fastcall TDispatchThread (bool CreateSuspended,HANDLE h)
    : TThread(CreateSuspended)
    , hCom(h)
{
 ; // остальные действия 
}

и даже вернул его назад на неконстантный, на всякий случай. Всё равно не компилируется

Автор: mes 17.7.2008, 10:18
ksili, покажи описание класса и код ошибки 


Автор: ksili 17.7.2008, 11:37
DispatchThread.h
Код

class TDispatchThread : public TThread
{
private:
protected:

// тут куча функций

public:
__fastcall TDispatchThread(bool CreateSuspended, HANDLE h);
// дальше куча переменных
........
// одну из них хочу сделать константной
 /*const*/ HANDLE hCom;          // const можно и раскомментировать, ничего не изменится
};

DispatchThread.cpp
Код

__fastcall TDispatchThread(bool CreateSuspended, HANDLE h)
    : TThread(CreateSuspended)
    , hCom(h)
{
 // всякие действия. h и hCom не используются
}

другого конструктора нету. Класс TThread не мой - объявлен в Classes.hpp

В основном процессе экземпляр моего класса TDispatchThread создается так:
Код

pdt = new TDispatchThread(true, port);


Коды ошибок:
E2275 { expected
E2040 Declaration terminated incorrectly
обе ошибки на одной строке в DispatchThread.cpp:  : TThread(CreateSuspended)

Автор: vinter 17.7.2008, 11:48
а попробуй написать так
Код

__fastcall TDispatchThread(bool CreateSuspended, HANDLE h) : TThread(CreateSuspended) , hCom(h)
{}

т.е в одну строку.

Автор: ksili 17.7.2008, 11:53
vinter, ничего не изменилось

Автор: mes 17.7.2008, 11:55
на вид все правильно у тебя, проверька на своем компиляторе этот код :
Код

class A { public: A (int b) {} };
class B : public A
{
    public:
    B (int _i1, int _i2, int _i3) : A(_i1), i(_i2), ci(_i3) {}
    int i;
    const int ci;
};


Автор: Lazin 17.7.2008, 12:10
попробуй 
Код

TThread(TThread::CreateSuspended) 

Автор: UnrealMan 17.7.2008, 12:19
Цитата(Ulysses4j @  17.7.2008,  09:44 Найти цитируемый пост)
Не может быть проблемы в несоответствии порядка объявления порядку в листе инициализации?

Кроме читабельности от порядка инициализаторов в списке инициализации не зависит ровным счётом ничего. И константность в этом плане ни на что не влияет.

Автор: ksili 17.7.2008, 12:26
Цитата(mes @  17.7.2008,  15:55 Найти цитируемый пост)
на вид все правильно у тебя, проверька на своем компиляторе этот код :
Код

class A { public: A (int b) {} };
class B : public A
{
    public:
    B (int _i1, int _i2, int _i3) : A(_i1), i(_i2), ci(_i3) {}
    int i;
    const int ci;
};

Проверил: как консольное скомпилировалось без проблем, а как VCL - скомпилировалось, но при запуске происходит исключение в конструкторе формы

Lazin, попробовал - не помогло

Автор: mes 17.7.2008, 12:35
Цитата(UnrealMan @  17.7.2008,  12:19 Найти цитируемый пост)
Кроме читабельности от порядка инициализаторов в списке инициализации не зависит ровным счётом ничего. И константность в этом плане ни на что не влияет. 

при несоблюдении порядка в списке инициализации мой компилятор начинает кричать о несправедливости ))


Цитата(ksili @  17.7.2008,  12:26 Найти цитируемый пост)
попробовал - не помогло 

что то я запутался, а с таким коструктором компилится ? :
Код

__fastcall TDispatchThread(bool CreateSuspended, HANDLE h)  : TThread(CreateSuspended)  {} 



Автор: UnrealMan 17.7.2008, 12:42
Цитата(mes @  17.7.2008,  12:35 Найти цитируемый пост)
при несоблюдении порядка в списке инициализации мой компилятор начинает кричать о несправедливости ))

В виде предупреждений или ошибок?

Автор: mes 17.7.2008, 12:46
Цитата(UnrealMan @  17.7.2008,  12:42 Найти цитируемый пост)
В виде предупреждений или ошибок? 

предупреждение 

Автор: UnrealMan 17.7.2008, 12:50
Цитата(mes @  17.7.2008,  12:46 Найти цитируемый пост)
предупреждение 

Ну, тем самым компилятор намекает на плохую читабельность smile

Автор: Ulysses4j 17.7.2008, 12:57
Цитата(UnrealMan @  17.7.2008,  13:19 Найти цитируемый пост)
Кроме читабельности от порядка инициализаторов в списке инициализации не зависит ровным счётом ничего. И константность в этом плане ни на что не влияет.

Да, ошибся: сложности возникают, если есть зависимости между инициализацией разных членов класса. В списке инициализировали один член, потом с его помощью второй, но если в реальности они будут инициализироваться в обратном порядке (если объявлены в другом), то будут проблемы.

Автор: ksili 17.7.2008, 12:58
А-а-а!!! вот я идиот! Забыл вот это: TDispatchThread::
Код

__fastcall TDispatchThread::TDispatchThread(bool CreateSuspended, HANDLE h)  : TThread(CreateSuspended)  {} 

Теперя всё компилится

Автор: mes 17.7.2008, 13:03
Цитата(ksili @  17.7.2008,  12:58 Найти цитируемый пост)
Забыл вот это: TDispatchThread::

приятно слышать, что разобрался со своей проблемой  smile 



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)