Тема: Глобальні змінні (або статичні у класі)

Не раз стикався з такою проблемою: потрібно між об'єктами різних класів передати данні.
Наприклад: Є класи А, В, С вони по різному опрацьовують setValue, мають вставляти дані в один і той самий стек.
Як бути в такому випадку ?

#include <iostream>
#include <stack>

std::stack<int> values;

class A
{
public:
    virtual const int &getValue() const
    {
        int &a = values.top();
        values.pop();
        return a;
    }
    virtual void setValue(const int &value)
    {
        values.push(value + 1);
    }
};

class B : public A
{
public:
    void setValue(const int &value) override
    {
        values.push(value + 2);
    }
};

class C : public A
{
public:
    void setValue(const int &value) override
    {
        values.push(value + 3);
    }
};

int main()
{
    A obj1;
    obj1.setValue(5);
    B obj2;
    obj2.setValue(5);
    C obj3;
    obj3.setValue(5);
    
    std::cout<<obj1.getValue()<<'\n';
    std::cout<<obj1.getValue()<<'\n';
    std::cout<<obj1.getValue()<<'\n';
    return 0;
}

Чому в класах С++ не можна створити статичну змінну ?

static std::stack<int> values;

Пробував якось обійти це... (хоча це ще гірший варіант...)

#include <iostream>

template<typename T>
class A
{
public:
    static T &getStaticVar(const T &setStaticVar = 0)
    {
        static T staticVar = 0;
        if(setStaticVar != 0)
            staticVar = setStaticVar;
        return staticVar;
    }
};

int main()
{
    A<int> obj;
    obj.getStaticVar(5);/*Встановлюю 5 у об'єкт obj*/
    
    std::cout<<A<int>::getStaticVar();/*беру значення без жодного об'єкту*/
    
    return 0;
}

Що ж все таки робити, створювати глобальну змінну в просторі імен, використовувати патерни (як singleton наприклад), чи є, інша, краща ідея ?

2

Re: Глобальні змінні (або статичні у класі)

Betterthanyou написав:

Чому в класах С++ не можна створити статичну змінну ?

static std::stack<int> values;
struct A {
    static std::stack<int> values;
};

std::stack<int> A::values;

int main() {
    A::values.push(1);
}
Подякували: koala, Betterthanyou, LoganRoss, leofun014

3

Re: Глобальні змінні (або статичні у класі)

Розжую відповідь Yola: якщо проголошення статичної змінної буде лише в хедері, то вона проголошуватиметься окремо в кожній одиниці компіляції, яка цей хедер використовує, а це не те, що треба. Тому проголошення в хедері розглядається як попереднє, а конкретно виділення пам'яті та ініціалізація - у відповідному .cpp-файлі.

Подякували: Betterthanyou, Yola, leofun013

4 Востаннє редагувалося Betterthanyou (05.03.2018 16:54:11)

Re: Глобальні змінні (або статичні у класі)

Я вибачаюсь не все зрозумів..., ось, наприклад, в мене є файли: Source.cpp, Source1.cpp, Header.h, Header1.h, якщо потрібно поширити (оголосити) глобальну змінну - можна скористатися extern'ом, але оскільки використовується статична змінна, extern не може бути застосованим...

koala написав:

а конкретно виділення пам'яті та ініціалізація - у відповідному .cpp-файлі.

ось тут якраз не зрозумів

якщо в Source.cpp написати "std::stack<int> A::values;" (виділити пам'ять), помилка Error    C2086    'std::stack<int,std::deque<_Ty,std::allocator<_Ty>>> A::values': redefinition

Якщо цього не робити LNK1169    one or more multiply defined symbols found

Якщо використати extern Error    C2720    'A::values': 'extern ' storage-class specifier illegal on members

Source.cpp

#include <iostream>
#include "Header.h"
#include "Header1.h"

int main()
{
    MyClass myClass;
    A::values.push(1);

    getchar();
    return 0;
}

Header.h

#pragma once

#include <stack>

class A
{
public:
    static std::stack<int> values;
};

std::stack<int> A::values;

Source1.cpp

#include "Header1.h"
#include "Header.h"

MyClass::MyClass()
{
    A::values.push(1);
}

Header1.h

#pragma once

class MyClass
{
public:
    MyClass();
};

Можете показати на прикладі як це зробити, або більш детальніше пояснити ?

приклад з глобальною змінною

Source.cpp

#include <iostream>
#include "Header.h"
#include "Header1.h"

std::stack<int> values;

int main()
{
    MyClass myClass;
    values.push(1);

    getchar();
    return 0;
}

Header.h

#pragma once

#include <stack>

class A
{
public:
    
};

extern std::stack<int> values;

Source1.cpp

#include "Header1.h"
#include "Header.h"

MyClass::MyClass()
{
    values.push(1);
}

Header1.h

#pragma once

class MyClass
{
public:
    MyClass();
};

5

Re: Глобальні змінні (або статичні у класі)

Header - тільки

class A
{
public:
    static std::stack<int> values;
};

Source -

std::stack<int> A::values;

Ви визначили A::values двічі - у хедері та в сорсі. А треба в хедері тільки проголошення лишити.

Подякували: Betterthanyou, leofun012