Попытка изменить статическую переменную родительского класса A для всего дочернего класса B - PullRequest
0 голосов
/ 25 апреля 2019

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

Заголовочный файл:

class A {
public:
    A() {}

    void printName() {qDebug() << _name; }    
    void changeName(QString name) {_name = name;}

private:
    static QString _name;
};
QString A::_name = QString("default");

class B : public A {
public:
    B() : A() {}
};

class C : public A {
public:
    C() : A() {}    
};

Я пытаюсь отредактировать статическое имя моего класса B без редактирования имени моего класса C. Когда я пытаюсь этот код в этом main.cpp:

int main(int argc, char *argv[])
{
    A *a = new B{};
    A *b = new B{};
    A *c = new C{};

    a->printName();
    b->printName();
    c->printName();

    B *tmp = dynamic_cast<B*>(a);
    tmp->changeName("new");

    qDebug() << "Then";    

    a->printName();
    b->printName();
    c->printName();
}

Вот что у меня есть:

"default"
"default"
"default"
Then
"new"
"new"
"new"

Кто-нибудь знает, как я могу это исправить?

Вот что я тоже попробую:

class A {
    public:
    A() {}
    virtual ~A() {}

    void printName() {qDebug() << _name; }

    virtual void changeName(QString name) {_name = name;}
    private:
    static QString _name;
};

QString A::_name = QString("default");

class B : public A {
public:
    B() : A() {}

    void changeName(QString name) override {_name = name;}
private:
    static QString _name;
};

class C : public A {
public:
    C() : A() {}

    void changeName(QString name) override {_name = name;}
private:
    static QString _name;
};

1 Ответ

1 голос
/ 25 апреля 2019

Существует только один A::_name, он может иметь только одно значение в любой момент времени. Поскольку все ваши производные типы используют один и тот же элемент static, все они обязательно имеют одинаковое значение _name. Чтобы исправить это, каждый производный тип должен предоставить свой собственный static член.

Чтобы не повторять одни и те же члены в каждом производном типе, вы можете определить их в шаблонном промежуточном классе, который находится между A и производными типами B и C. У каждой специализации шаблона есть свой static член. Таким образом, при условии, что каждый производный тип предоставляет уникальное значение для аргумента шаблона промежуточного типа, они будут иметь свои собственные имена. Например, разделите A на два класса:

#include <iostream>
#include <string>

class A {
public:
    virtual void printName() = 0;
    virtual void changeName(std::string name) = 0;
};

template<class T>
class A_impl : public A
{
public:
    void printName() override { 
        std::cout << _name << '\n';
    };
    void changeName(std::string name) override { 
        _name = std::move(name);
    };

private:
    static std::string _name;
};

template<class T>
std::string A_impl<T>::_name = "default";

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

class B : public A_impl<B> { };

class C : public A_impl<C> { };

Теперь ваш тест должен напечатать

default
default
default
Then
new
new
default
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...