-1

I want to set a reference after constructor

Example:

class OtherClass
{
public:
    OtherClass() : m_class(Class()){}

    inline void SetData(int data1, int data2)
    {
        //calculate data3

        // I tried:
        m_class = Class(data3);
        //but it doesn't worked
    }

protected:
private:
    Class& m_class;
};

Edit:

  • The Exception is: vector subscript out of range because I have glm vectors in the Class.
  • I need also call functions in my Class.

Edit 2:

Why I need this? Because I have an other class [ExClass] which extends and which have to calulate in constructor:

ExClass::ExClass(float d1, float d2, ...) {
//calculate data from given values
SetData(data); 
}
Freddy C.
  • 119
  • 2
  • 11
  • What is the error messag that you have? Do 'Class' have a constructor for (int,int) ? – Luc May 11 '18 at 16:41
  • 2
    Why are you making it a reference to begin with? – 001 May 11 '18 at 16:42
  • **Thanks for your comments. I simplified the example** and I am using my Vertex Class. **The Exception is: vector subscript out of range** – Freddy C. May 11 '18 at 16:44
  • (I have glm vectors in my Vertex class) – Freddy C. May 11 '18 at 16:45
  • This question is very unclear. It is neither clear what you are trying to do nor how it does not work. Please [edit] your question to provide a [mcve] as well as a clear problem statement. – Baum mit Augen May 11 '18 at 16:46
  • References can’t be rebound like this. If you want something rebindable, you need to use a pointer (or a smart pointer object), which lets you do both rebinding and assignment by having different syntax (`p = …` vs `*p = …`). The whole point of a reference is that its `p = …` acts like a pointer’s `*p = …`; if you don’t want that, don’t use one. – abarnert May 11 '18 at 16:47
  • Ok thanks. I will try it. – Freddy C. May 11 '18 at 16:48
  • @abarnert Is it also possible to run function of a pointer of a class? – Freddy C. May 11 '18 at 16:49
  • Why "setData"? Why not construct in the constructor? What are you trying to accomplish? In other words, why do you think you need this? – Jive Dadson May 11 '18 at 17:12
  • Can't be done. Once a reference variable refers to (aliases) one variable, it always references that variable. That is by design. – Jive Dadson May 11 '18 at 17:55
  • Possible duplicate of [Why can I assign a new value to a reference, and how can I make a reference refer to something else?](https://stackoverflow.com/questions/7181372/why-can-i-assign-a-new-value-to-a-reference-and-how-can-i-make-a-reference-refe) – Jive Dadson May 11 '18 at 18:04
  • @JiveDadson Why "setData"?: Because I have an other class which extends and which have to calulate in constructor: OtherClass::OtherClass(glm::vec3 position, float side) { //calculate data from given values SetData(data); } – Freddy C. May 11 '18 at 19:21

2 Answers2

1

The proper way to do that is to use a pointer and not a reference, as opposed to references - pointers can be set after object creation. Note also that referring (or pointing) to a local variable whose lifetime will end, while still in use, is a bad idea.

Your code may be changed to use a pointer and dynamic allocation or alternatively, std::unique_ptr. There are of course other options, these are just examples.

Option 1 - a pointer and dynamic allocation

class OtherClass
{
public:
    OtherClass() : m_class(nullptr){}
    ~OtherClass() {
        delete m_class;
    }

    // block copy and assignment (or implement them)
    OtherClass(const OtherClass&) = delete;
    OtherClass& operator=(const OtherClass&) = delete;

    void setData(int data1, int data2)
    {
        // ... calculate data3 ...

        m_class = new Class(data3);
    }
    bool hasInnerObj() const {
        return m_class; // or: return m_class != nullptr;
    }
    /** call this function only if hasInnerObj() returned true */
    Class& getInnerObj() {
        return *m_class;
    }
private:
    Class* m_class;
};

Option 2 - std::unique_ptr

class OtherClass
{
public:
    void setData(int data1, int data2)
    {
        // ... calculate data3 ...

        m_class = std::make_unique<Class>(data3);
    }
    bool hasInnerObj() const {
        return m_class; // or: return m_class != nullptr;
    }
    /** call this function only if hasInnerObj() returned true */
    Class& getInnerObj() {
        return *m_class;
    }
private:
    std::unique_ptr<Class> m_class;
};
Amir Kirsh
  • 12,564
  • 41
  • 74
0

You have two problems:

  1. Reference class members (i.e. m_class) need to be initialized when object is created.
  2. However, both your Class instances (one in the constructor, and one in SetData) are put on the stack and popped right away, making the reference invalid.

What you need to do is make sure that your class object actually lives through the function call. One way of achieving that is allocating it prior to passing it to the OtherClass constructor or SetData function:

class Class {};

class OtherClass
{
public:
    OtherClass(Class& c) : m_class(c){}

    inline void SetData(Class& c)
    {
        m_class = c;
    }

protected:
private:
    Class& m_class;
};

int main()
{
    Class a;
    OtherClass c(a);

    Class b;
    c.SetData(b); // changes m_class

    return 0;
}

Live example here.

Domi
  • 22,151
  • 15
  • 92
  • 122
  • This is not what the OP wants, and I suspect, not what you intend. It changes the `Class a` defined in `main()` to have the contents of `Class b` in `main()`. I think he wants `Class& m_class` to refer first to `a` and then to `b`, which cannot be done. In other words, the comment "changes m_class" is wrong. It changes the object that m_class refers to, namely 'a'. – Jive Dadson May 11 '18 at 17:48
  • @JiveDadson Changing `a` (or whatever reference `m_class` currently holds) might or might not be intended. Your guess is as good as mine. Since he is working with `vector3` stuff representing position, I am guessing, at this point, that he wants `Class m_class` and not `Class &m_class`. – Domi May 12 '18 at 11:58