почему трубуется static?

 
0
 
C++
ava
mrgloom | 18.02.2013, 18:19

class CMyDlg : public CDialog
{

    class CMyTask : public CThreadClass::CTaskClass
    {
    public:
        int         var;

        CMyTask() :
        var(0)
        {}

        virtual void Execute()
        {

            double val = CMyDlg::Calc(var); //требует чтобы Calc было static illegal call of non-static member function

        }
    };
    
    //....
    
private:
    double Calc(var);
public:
    int m_some_const;
}


требует чтобы Calc было static, но Calc внутри зависит от m_some_const и соответсвенно её тоже надо делать тогда статик, но тогда
Цитата


unresolved external symbol "public: static int CMyDlg::m_some_const


как разрешить проблему и как правильно?
Ответы (20)
ava
Alexeis | 18.02.2013, 18:02 #
  Он требует статик потому что в функцию Execute не передан указатель на CMyDlg .  С ним можно было написать MyDlg->Calc(var); не делая Calc статической
ava
Albor | 18.02.2013, 18:06 #
Вы вызываете не статическую функцию класса не создав объект, поэтому компилятор и ругается. Соответственно, после того как функция объявлена как статическая, она не может использовать не статические поля.
ava
korian | 18.02.2013, 18:54 #
Цитата (mrgloom @  18.2.2013,  16:19 findReferencedText)
double val = CMyDlg::Calc(var);

похоже на попытку писать как на java. В c++, внутренний класс не содержит в себе автоматом ссылку на внешний класс. Т.е. в c++ они все static как бы. При этом к приватным  полям доступа тоже кажись не дадут. (Не помню).
Можно починить так как ниже, но это наверно не лучший вариант.


class CMyDlg : public CDialog
{
    class CMyTask : public CThreadClass::CTaskClass
    {
    public:
        CMyDlg &m_dlg;
        int         var;
        CMyTask(CMyDlg &dlg) :
        m_dlg(dlg)
        var(0)
        {}
        virtual void Execute()
        {
            double val = m_dlg.Calc(var); //требует чтобы Calc было static illegal call of non-static member function
        }
    };
    
    //....
    
private:
    friend class CMyTask;
    double Calc(var);
public:
    int m_some_const;
}


Добавлено позднее:
Цитата (mrgloom @  18.2.2013,  16:19 findReferencedText)
unresolved external symbol "public: static int CMyDlg::m_some_const

не константные static переменные должны быть определены в cpp-файле (в добавок к определению в h-файле).

static int CMyDlg::m_some_const = 0;
ava
mrgloom | 19.02.2013, 10:13 #
Цитата


Вы вызываете не статическую функцию класса не создав объект, поэтому компилятор и ругается. Соответственно, после того как функция объявлена как статическая, она не может использовать не статические поля. 



Цитата


не константные static переменные должны быть определены в cpp-файле (в добавок к определению в h-файле).



static int CMyDlg::m_some_const = 0;




эти ответы помогли, только надо

int CMyDlg::m_some_const = 0;


А почему плохое решение?

CMyDlg &m_dlg;  //непонятно разве так можно объявлять переменную?
        int         var;
        CMyTask(CMyDlg &dlg) :
        m_dlg(dlg)
ava
korian | 19.02.2013, 17:04 #
Цитата (mrgloom @  19.2.2013,  09:13 findReferencedText)
А почему плохое решение?

Если надо писать "friend class ...", то я автоматом считаю решение не хорошим. Но я ничего не могу сказать по поводу того, почему оно плохое. Т.е. надо знать пороблему и понять, можно ли сделать по другому (обычно можно).


Цитата (mrgloom @  19.2.2013,  09:13 findReferencedText)
//непонятно разве так можно объявлять переменную?

да, я запятую пропустил, после m_dlg(dlg)
ava
Alexeis | 20.02.2013, 09:22 #
Цитата (korian @  19.2.2013,  18:04 findReferencedText)
Если надо писать "friend class ...", то я автоматом считаю решение не хорошим.
 Ну да, наверное, дураки придумали это ключевое слово для дураков. Наверное, и слово декомпозиция для вас ругательное. Вот как раз, когда разбивают задачу на подзадачи с применением ООП возникает необходимость формировать сильные связи внутри группы объектов, которые по логике являются сильно связанными. Именно для этого и существует friend для обозначения группы сильно связанных объектов, которые решают подзадачи одной более сложной задачи. Если же friend используется для написания кода слабо связанных объектов, то это действительно нехорошее решение.
  Грубо говоря, если А предназначено для B, то А является другом для B, что и реализует модификатор friend. 
ava
mrgloom | 20.02.2013, 10:56 #
ну я в итог сделал const функцию и переменную. вроде бы это особых ограничений не накладывает.


я говорил про строчку

CMyDlg &m_dlg;


т.е. когда так в функцию передается понятно аля  func(CMyDlg &m_dlg), а что значит когда так объявляется переменная?
ava
Alexeis | 20.02.2013, 12:27 #
  Это значит, что функция ожидает в качестве параметра ссылку на переменную. Ссылка это некоторое подобие указателя с той лишь разницей, что ссылка всегда указывает на реально существующую переменную. Ссылка это некоторый псевдоним переменной, поэтому при обращении к полям или функциям объекта синтаксис как у переменной. Ссылка инициализируется в момент создания и дальше не уже не может менять свою привязку к переменной. К примеру, переменная это ни что иное как адрес некоторой области памяти. Вот если 2е переменные определяют одну и ту же область памяти, то одна из переменных является ссылкой. Не путать с указателем. Указатель хранит адрес на этапе исполнения, а переменная (ссылка) хранит данные по некоторому адресу в памяти. 
ava
korian | 20.02.2013, 14:12 #
Цитата (Alexeis @  20.2.2013,  08:22 findReferencedText)
Если же friend используется для написания кода слабо связанных объектов, то это действительно нехорошее решение. 

По моему опыту, в 99.99% так оно и есть. Т.е. если friend используется в коммерческом проекте (не библиотека, или шо-то другое, что должно быть сверх унифицировано), то он используется именно там, где он нафиг не нужен.
Цитата (Alexeis @  20.2.2013,  08:22 findReferencedText)
Ну да, наверное, дураки придумали это ключевое слово для дураков.

Слово придумали для того, чтобы можно было сделать все, что может только потребоваться.
Я например не собираюсь использовать слово volatile в одно-поточном приложении. Но в c++ оно есть.
При чем я его не буду использовать даже там, где теоретически я могу сделать доступ из несколько потоков (продумать на будущее, написать более унифицировано, так сказать), потому что у меня все равно приложение будет одно-поточное.

оператор delete, кстати, туда же к friend. Т.е. я считаю, что в реальном проекте использовать его нельзя.
Использовать его есть смысл только в небольших участках кода, которые требуют оптимизации, что по моему опыту не более 0.01% случаев и реальный коммерческий проект в них никогда не попадает.
ava
Alexeis | 20.02.2013, 17:28 #
Цитата (korian @  20.2.2013,  15:12 findReferencedText)
По моему опыту, в 99.99% так оно и есть. Т.е. если friend используется в коммерческом проекте (не библиотека, или шо-то другое, что должно быть сверх унифицировано), то он используется именно там, где он нафиг не нужен.


По-моему опыту, браться на С++ писать что-то сверх унифицированное уже ошибка. Язык максимально ориентирован на статическое связывание решение системных высокопроизводительных задач. Все вкусняжки языка в шаблонах/ссылках/инлайнах/константах/типах времени компиляции. Короче, то что генерится на этапе компиляции. В STL/Boost виртуальных методов не встретишь. Как раз эти самые сильные связи наилучшее, что можно творить на С++ .
Цитата (korian @  20.2.2013,  15:12 findReferencedText)
Я например не собираюсь использовать слово volatile в одно-поточном приложении. Но в c++ оно есть.


  Ну если данные меняются в прерывании, то без него никуда. Что такое С++ ? Высокопроизводительные движки типа сервера бд (например firebird), драйвера и системные утилиты, движки 3D игр, веб сервера, математические движки типа Матлаб, среды симуляции LabView, прошивки контроллеров (ПЛК), элементы ОС. Как тут жить без volatile и friend потоков и прерываний?  

Про оператор delete вообще smile .

P.S. Чувствую, ща придется тему разделять и флуд отсюда отрезать.

ava
korian | 20.02.2013, 17:38 #
Цитата (Alexeis @  20.2.2013,  16:28 findReferencedText)
По-моему опыту, браться на С++ писать что-то сверх унифицированное уже ошибка. 

как бы тот же boost я считаю уже чем-то сверх унифицированным, писать его - ошибка?
и, в принципе, не понял, как весь первый абзац относится к friend?
дайте реальный пример, где вы считаете, что friend необходим, я покажу вам, как от него избавиться. Причем в результате код получиться более читабельным.

Цитата (Alexeis @  20.2.2013,  16:28 findReferencedText)
ро оператор delete вообще 

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

Цитата (Alexeis @  20.2.2013,  16:28 findReferencedText)
Как тут жить без volatile и friend потоков и прерываний?  

где я написал, что эти слова в языке не нужны совсем? я такого не писал.
ava
Alexeis | 20.02.2013, 18:28 #
Цитата (korian @  20.2.2013,  18:38 findReferencedText)
дайте реальный пример, где вы считаете, что он нужен, я покажу как от него избавиться.

  Реальный пример будет не на одну сотню строк, так что вот псевдокод.


template<typename T>
class SubTaskA<T>
{
T &Parent; 
public:
        SubTaskA(T &aParent)Parent(aParent){}
    bool ExecuteSubtask(...)
    {
        ReadFromDevice(val);
                pr_val = ProcessVal(val);
        WriteToDevice(pr_val);
                Parent.UpdateInternalParentState(pr_val);
    }
};

class TaskA
{
friend SubTaskA<TaskA>;
protected:
    SubTaskA<TaskA> Task1;
    void UpdateInternalParentState(...);
public:
    TaskA( void ) : Task1(*this){};    
    void DoTask()
    {
        Task1.ExecuteSubtask(...);
        Task2.ExecuteSubtask(...);
    }

};


Цитата (korian @  20.2.2013,  18:38 findReferencedText)
где я написал, что эти слова в языке не нужны совсем? я такого не писал. 

   Так я и не опровергал утверждение, о том что они совсем не нужны. Я опровергал, то что они редко используются в реальных проектах на С++ . Специфика языка такова, что эти модификаторы не просто дополнительные придатки, а основной рабочий механизм. 
ava
korian | 20.02.2013, 18:43 #
учитывая, что это псевдокод, то у для меня тут или в классе TaskA, функция UpdateInternalParentState должна быть public.
Или второй вариант (тоже псевдокод):

template<typename T>
class SubTaskA<T>
{
typedef ... UpdateFunction;
UpdateFunction listener;
public:
        SubTaskA(UpdateFunction aParent)listener(aParent){}
    bool ExecuteSubtask(...)
    {
        ReadFromDevice(val);
                pr_val = ProcessVal(val);
        WriteToDevice(pr_val);
                listener(pr_val);
    }
};
class TaskA
{
protected:
    SubTaskA<TaskA> Task1;
    void UpdateInternalParentState(...);
public:
    TaskA( void ) : Task1(&UpdateInternalParentState){};    
    void DoTask()
    {
        Task1.ExecuteSubtask(...);
        Task2.ExecuteSubtask(...);
    }
};


Не нравится передача указателя на функцию или функций больше чем одна - можно использовать интерфейс (в смысле полиморфизм).
ava
NoviceF | 20.02.2013, 21:27 #
Цитата (korian @  20.2.2013,  15:12 findReferencedText)
оператор delete ... в реальном проекте использовать его нельзя.


А можно тут небольшое пояснение? Как удалять объекты выделенные new?
ava
korian | 21.02.2013, 02:19 #
Цитата (NoviceF @  20.2.2013,  20:27 findReferencedText)
А можно тут небольшое пояснение? Как удалять объекты выделенные new? 

В зависимости от ситуации.
Есть в c++11 std::unique_ptr (заменители: std::auto_ptr, boost:scoped_ptr)
есть std::shared_ptr/std::weak_ptr (boost::shared_ptr/boost::weak_ptr)
для массивов - std::vector
ava
math64 | 21.02.2013, 08:25 #
Вложенный класс имеет доступ к private полям и методам внешнего (но нужен указатель на внешний класс), поэтому friend не нужен.
ava
mrgloom | 21.02.2013, 09:03 #
Цитата (Alexeis @  20.2.2013,  12:27 findReferencedText)
Это значит, что функция ожидает в качестве параметра ссылку на переменную. Ссылка это некоторое подобие указателя с той лишь разницей, что ссылка всегда указывает на реально существующую переменную. Ссылка это некоторый псевдоним переменной, поэтому при обращении к полям или функциям объекта синтаксис как у переменной. Ссылка инициализируется в момент создания и дальше не уже не может менять свою привязку к переменной. К примеру, переменная это ни что иное как адрес некоторой области памяти. Вот если 2е переменные определяют одну и ту же область памяти, то одна из переменных является ссылкой. Не путать с указателем. Указатель хранит адрес на этапе исполнения, а переменная (ссылка) хранит данные по некоторому адресу в памяти. 

это то понятно.


CMyDlg &m_dlg;  // разве не должно быть CMyDlg m_dlg; ?
CMyTask(CMyDlg &dlg) : //эта строчка понятна
ava
Alexeis | 21.02.2013, 10:17 #
  Это с зависимости от того чего хотят добиться. Если хотят иметь копию объекта класса CMyDlg тогда пишется CMyDlg m_dlg; если же хотят чтобы CMyTask хранил ссылку на созданный ранее или разделяемый объект, то пишут CMyDlg &m_dlg; 

Цитата (korian @  20.2.2013,  19:43 findReferencedText)
Не нравится передача указателя на функцию или функций больше чем одна - можно использовать интерфейс (в смысле полиморфизм).

  Зачем же мне городить огород с поздним связыванием? С виртуальными функциями, абстрактными интерфейсами и т.д. когда я могу связать все статически? Мало что это раздувает код, так оно еще делает его тормозным. При желании я вообще могу сделать ExecuteSubtask инлайном и получить максимальное быстродействие. Компилятор С++ умеет эффективно оптимизировать статичные связки. Например, он может легко выкинуть реализацию неиспользуемой простой функции, тогда как виртуальная всегда попадает в исполняемый файл. Это сколько нужно делать лишних движений, чтобы заменить один модификатор friend в том случае когда он находиться на своем месте. Вопрос ЗАЧЕМ ЭТО ДЕЛАТЬ?

Цитата (korian @  20.2.2013,  19:43 findReferencedText)
функция UpdateInternalParentState должна быть public

Функция должна быть паблик, если ее может вызвать из любой другой функции которая имеет доступ к объекту. В моем случае класс-хелпер (делегат) реализует внутреннюю логику, поэтому ему нужен доступ закрытым полям и функциям. 
ava
mrgloom | 21.02.2013, 11:19 #
ну тут написано http://ru.wikipedia.org/wiki/%D0%A1%D1%81%...0_%28C%2B%2B%29
Цитата


Ссылки нельзя объявлять без привязки к переменной (то есть не инициализировав при объявлении).


или когда мы объявляем в классе, то можно?
ava
Alexeis | 21.02.2013, 11:56 #
  Так мы ее инициализируем в объявлении. Только не в объявлении поля (синтаксис С++ запрещает инициализировать поля при описании), а при объявлении класса в конструкторе. Не может получиться такого, что объект создан а ссылка не инициализирована. 
Зарегистрируйтесь или войдите, чтобы написать.
Фирма дня
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Участники
advanced
Отправить