C ++ инициализирует указатель класса через функцию - PullRequest
0 голосов
/ 28 мая 2018

У меня есть программа, у которой есть один экземпляр класса class A и много экземпляров класса class B, где каждый экземпляр class B имеет указатель на один экземпляр class A.Я думал, что смогу инициировать их в main(), а затем передать адрес одного экземпляра class A всем экземплярам class B.Я хочу знать, если это правильно, я смотрел на наследование, но из моего понимания (что часто неправильно), если вы наследуете другой класс, тогда этот класс инициируется каждый раз, так что создается отношение многие ко многим, тогда как, я хочу одинслишком много.Я приложил некоторый код.Любые предложения будут с благодарностью.

// C/C++ standard library
#include <vector>
#include <iostream>
#include <cstdlib>

using namespace std;

class A {
public:
    double get_value(void) {
        return value;
    }
private:
    double value;
};


// Forward declare A if split over files
class B {
public:
    void assign_pointer(A class_a_to_assign) {
        class_a = &class_a_to_assign; // assign the pointer the address to point to
    }
    void update_my_value(void) {
        value_b += class_a->get_value();
    }

    double get_value(void) {
        return value_b;
    }
private:
    double value_b = 0.1;
    A* class_a; // pointer to class A
};

int main() {
    cout << "hello world" << endl;
    // create 2 instances of B there could be thousands of these tho.
    B b1;
    B b2;
    // create 1 instance of A
    A a1;

    // Now I want both instances of the B class to point to the one instance of A
    b1.assign_pointer(a1);
    b2.assign_pointer(a1);

    // THen do stuff with B so that if any changes occur in A, then they can be automatically updated in class B through the pointer

    b1.update_my_value();
    b2.update_my_value();

    cout << b1.get_value() << " and " << b2.get_value() << endl;
    return 0;
}

Ответы [ 3 ]

0 голосов
/ 28 мая 2018

То, что вы описали, звучит очень похоже на синглтон .Один способ, которым это часто обрабатывается, состоит в том, чтобы синглтон-класс включал метод static, который возвращает один экземпляр класса.Так это будет выглядеть примерно так:

class A {
    public:
        A() { /* constructor */ }
        ~A() { /* destructor */ }
        static A* getInstance();
        double get_value(void) {
            return value;
        }
    private:
        double value;
}; 

Метод static будет в файле реализации (.cpp) выглядеть примерно так:

static A gSharedInstance;

static A* A::getInstance()
{
    return &gSharedInstance;
}

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

A* sharedA = A::getInstance();
double value = sharedA->getValue(); // Or whatever you need from it.

Обратите внимание, что синглтон по сути является глобальной переменной, и у глобальных переменных есть некоторые проблемы.(Например, где его элемент value установлен в этом случае?) Но если класс представляет какой-то действительно уникальный ресурс (например, единственный микрофон на устройстве), то для его представления стоит иметь синглтон.В этом случае может быть лучше сделать его доступным только для чтения, чтобы его состояние не могло быть установлено во многих разных местах.Также имейте в виду, что вам может потребоваться добавить код для одновременного доступа к нескольким потокам.

0 голосов
/ 28 мая 2018

Прежде всего, в вашем коде есть серьезная проблема:

void assign_pointer(A class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

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

void assign_pointer(A &class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

Разница лишь в одном символе - амперсанд в объявлении аргумента функции превращает его из временного значения в ссылку на более долгоживущий объект.

Далее, если у вас есть один объект class A, вы рассматривали возможность сделать его одиночным?Таким образом, экземплярам B даже не нужно будет сохранять этот указатель, A сам управляет экземпляром.Там было много сказано о разработке одноэлементного класса, грубая и наивная реализация что-то вроде:

class A {
    A(); // note it's private
public:
    int getValue() const;
    static A &instance() {
        static A retVal;
        return A;
    };
};

class B {
public:
    void update_my_value(void) {
        value_b += A::instance().get_value();
    }
};

int main() {
    A::instance(); // to warmup the static instance before any users are created
    B b1; // no assign_pointer is needed as A is a Singleton
    B b2; // and every B always knows where to find it
}
0 голосов
/ 28 мая 2018

Ваше намерение создать только один экземпляр A и использовать указатель на этот экземпляр A нарушается в приведенной ниже функции.

void assign_pointer(A class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

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

  1. Вы создаете новый экземпляр A каждый раз, когда вызываете функцию.
  2. Вы храните указатель на временный объект.Указатель становится недействительным указателем, как только функция возвращается.

Вы можете исправить обе проблемы, сделав аргумент ссылочным типом.

void assign_pointer(A& class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

Также какКак уже упоминалось в комментариях, будет лучше создать объект A до объектов B, так как вы хотите, чтобы A пережил объекты B.

int main() {
    cout << "hello world" << endl;

    // create 1 instance of A
    A a1;

    // create 2 instances of B there could be thousands of these tho.
    B b1;
    B b2;

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