3

I've got the following class:

class BaseStyle {
    private:
        Style *style;
    public:
        BaseStyle(Style& theStyle);
        const Style& getStyle() const;
        void setStyle(const Style& theStyle);
};

I'm trying to store the reference passed in the constructor in style, and change that property when setStyle() is called. I expected to be able to have a property Style& style, however, then I read c++ reference properties can not be changed after initialization. Now I think it's best to store the reference in a pointer, but how do I do that? I can't just do style = theStyle, right?

Community
  • 1
  • 1
Frog
  • 1,631
  • 2
  • 17
  • 26

4 Answers4

1

You should implement your class like this:

class BaseStyle
{
    private:
        Style *style;
    public:
        BaseStyle(Style &theStyle) { style = &theStyle; }
        const Style &getStyle() const { return(*style); }
        void setStyle(Style &theStyle) { style = &theStyle; }
};

Explanation: References are implemented as pointers. This is not clearly stated in the docs by there is no compiler that is doing anything different from this. The difference is only syntactical. This means, that by writing &theStyle you take an address of the object that can be assigned to the pointer.

There is nothing bad in taking address of the object, referenced by the reference and assigning it to a pointer.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
  • Why do you write `return(*style);`? Wouldn't `return *style;` work as well? – Frog Aug 19 '12 at 20:05
  • I didn't downvote, guess someone else did. But thanks for the answer! – Frog Aug 19 '12 at 20:07
  • 1
    Implementation detail is exactly that and do not change the semantics of the language that have no bearing on how references are implemented. There is a reason the specs do not mention that references are implemented as pointers because they are not always and hemming the designers into a corner is counter productive. Even thinking of references as pointers hampers your ability to write good C++ (IMHO). – Martin York Aug 19 '12 at 23:22
  • > "pointers hampers your ability to write good C++" - any example? Otherwise this is a pointless statement. – Kirill Kobelev Aug 20 '12 at 00:43
  • 1
    @KirillKobelev: I agree it is a pointless "opinion". But just as pointless as "References are implemented as pointers" which is not always true. But it hampers the ability because the concepts are completely different. A references is an "Alias" nothing more nothing less. It is another name for an object and is nothing like a pointer which is itself an "object". – Martin York Aug 20 '12 at 01:07
  • "References are implemented as pointers" - this is always true. Any example when this is not so? Optimization will not work here. Optimization can do anything that is not breaking the logic. Optimization cases are countless. So far I do not see reasons from your side. "Another name" is plain wrong. Reference and referenced object may have different life span. – Kirill Kobelev Aug 20 '12 at 04:18
0

If you want to use pointers, change your class code to this:

class BaseStyle {
    private:
        Style *style;
    public:
        BaseStyle(Style* theStyle);
        Style* getStyle();
        void setStyle(Style* theStyle);
};

And then to set the style, do this:

First, create a pointer for the Style object you want to pass into setStyle:

Style* myStyle = new Style();

Then pass your myStyle object into the setStyle function:

baseStyleObj.setStyle(myStyle);

Or if baseStyleObj is also a pointer:

baseStyleObj->setStyle(myStyle);

Also it's bad practice to name variables the same as their class; your class member Style* should be named something other than style. m_style is one convention you could use (the m_ indicates it's a member variable), but there are many others. This doesn't affect the compilation of the code, of course; it's just good practice.

WendiKidd
  • 4,333
  • 4
  • 33
  • 50
  • 2
    Why is it bad practice to name it `style`? To me, allocating objects dynamically and keeping them in non-owning pointers is much worse. – R. Martinho Fernandes Aug 19 '12 at 19:33
  • @WendiKidd: I've read in a lot of place (also the link mentioned in my question) that one preferably shouldn't use pointers as parameter/return, because they can be `NULL` and because the coding style with pointers is different (`->` instead of `.`). Why don't you agree? – Frog Aug 19 '12 at 19:37
  • @Frog: I'm not sure why `->` vs `.` is an argument against using pointers. If you know you're going to be passed a pointer, you use `->`. Can you clarify that reasoning a bit more? I'm curious about that. As for the fact that pointers can be `NULL`, that's true. If everything is working properly, however, when you pass them to this function they shouldn't be--though as projects grow in size, bugs like this become more likely. So I suppose it's up to you, really. – WendiKidd Aug 19 '12 at 19:46
  • @WendiKidd: Some people argue that it's easier to later on change your code to a copy when using references, while when using pointers you're stuck with them. Although that obviously isn't a big problem, since you can just get a pointer. But I'm actually more curious why you think the naming of my variable is bad, could you elaborate on that? – Frog Aug 19 '12 at 19:49
  • @Frog It's not necessarily bad... It doesn't actually hurt anything. But I've always been told (and agreed myself) that naming a variable the same as the class isn't the best practice. Class `Style` and instance variable `style` are not the same thing, obviously. So the fact that their names differ by only 1 letter's capitalization can be confusing. It doesn't really hurt anything, it will just make the code easier to read. It's not going to affect your program; just thought I'd pass on my thoughts and the thoughts of others I've discussed this with. :) – WendiKidd Aug 19 '12 at 19:53
  • @WendiKidd: Okay, thanks for the advice. I'll think about it. ;) – Frog Aug 19 '12 at 19:55
  • @R.MartinhoFernandes it's bad practice because it makes your code harder to read and understand. Classes can have static members. If you're reading code later and see: style.read = 5; Does that affect a style object or the style class? What about this code: plus Plus = Plus(); What exactly is going on there? Doesn't make sense to go out of your way to make your code much harder to understand. – iheanyi Jul 21 '14 at 19:43
0

There is nothing wrong about passing a reference to the object and storing a pointer to the object:

class BaseStyle {
    private:
        Style *style;
    public:
        BaseStyle(Style& theStyle)              :style(&theStyle) {}
        const Style& getStyle() const           {return *style;}
        void setStyle(/*const*/ Style& theStyle){style = &style);}

                 //   ^^^^^^^^^ Your problems are caused becasue you passeded
                 //             a const reference but are storing the value in a non const
                 //             pointer. Just remove this const and it will compile.
};

The user of your class just has to know that the object is keeping an internal reference (not C++ reference) to the object passed and thus its lifespan must be as long as the object. Which is hinted at because you have a set method that takes a value by reference.

If you feel uncomfortable about using pointers directly you can use a boost::ref object.

class BaseStyle {
    private:
        boost::reference_wrapper<Style> style;
    public:
        BaseStyle(Style& theStyle)              :style(theStyle) {}
        const Style& getStyle() const           {return style;}
        void setStyle(/*const*/ Style& theStyle){style = boost::ref(style));}
};

This is basically a reference that can be re-seated. Note internally it uses a pointer but externally it behaves like a reference.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I have no problem with pointers, so boost is not needed. But thanks for the answer! – Frog Aug 20 '12 at 19:43
-1

You can store a reference in a pointer by doing

style = &theStyle;

However this is bad practice. If you're going to be storing it in a pointer, you should take in a pointer explicitly (and document the ownership semantics).

Also, setStyle is currently taking in a const ref. You need to change it to a regular reference if you want to store it in a non const pointer.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • 4
    Why is that bad practice? I've read in a lot of places that you preferably shouldn't use pointer as parameter/return. Also, doesn't the `const` keyword just mean that you can't change the value, not that you can't store it? – Frog Aug 19 '12 at 19:32
  • 5
    -1: The implementation of a class should not dictate its interface. Passing a reference is fine. How you represent it internally is neither here nor there. The class simply documents whether it copies the object being referred to or expects it to last for as long as it holds a reference. – Troubadour Aug 19 '12 at 19:36
  • @Troubadour: Glad not everything I read is wrong. :) But do you agree with Antimony that I should save the reference in a pointer, or do you think I should do this in a different way? – Frog Aug 19 '12 at 19:42
  • @Frog, People tend to miss, that your reference is not `const` and assume that data is copied. Using pointers usually tells to look more carefully class documentation. Then, of cause, `const` means you cannot change variable. But you also cannot assign unchangeable variable to changeable one. Otherwise all point of constantness will be lost. – Lol4t0 Aug 19 '12 at 19:43
  • @Lol4t0: Thanks for the explanation about `const`, I understand that now. But isn't to point of passing a reference that the data is not copied? Otherwise I would just pass by value, right? – Frog Aug 19 '12 at 19:46
  • @Frog Yes, that's correct :) It's also much slower to pass by value, since that copy has to be made. – WendiKidd Aug 19 '12 at 19:49
  • @Frog, it is usual pattern to pass values by const reference and then copy them to member variable (to avoid double coping first when you copy to method, second - when you copy to member variable). But when you call function, you can just miss that refernce is not const in this particular case. And you will get no warning, but you code will get broken. That is why, I think, `Qt` uses pointers in such situations, for example. – Lol4t0 Aug 19 '12 at 19:49
  • @Frog: If your class needs to change the thing being referred to then yes. A reference cannot be rebound but a pointer can be changed to point to something else. – Troubadour Aug 19 '12 at 19:49
  • @Lol4t0: But assuming you just read thoroughly, using references shouldn't be a problem, right? – Frog Aug 19 '12 at 19:53
  • 1
    @Frog, yes. I usually use references in such case, actually:) – Lol4t0 Aug 19 '12 at 19:55
  • @Lol4t0: Haha, +1 for that. How should I go about accepting an answer? Since neither answer fully says what I needed, should I create my own answer? – Frog Aug 19 '12 at 19:57
  • @Frog General consensus is that you pick the answer that helped you the most, and accept that one, whichever it may be. See this meta post for more information: http://meta.stackexchange.com/questions/119872/what-type-of-answer-should-i-accept – WendiKidd Aug 19 '12 at 20:04
  • @WendiKidd: Okay, guess I'll accept Kirill's answer then, since that is exactly what I was looking for. I'll up vote you though for the excellent help. – Frog Aug 19 '12 at 20:10
  • @Troubadour the reason I consider it bad practice is because (At least in my experience) it is highly unusual to store passed in references, so people who see a reference will probably just assume you took a reference in order to make a quick change to the referred to variable and blithely pass in references to locals and the like. If you take a pointer, they'll have to actually check the documentation to see what kind of ownership semantics you're using. It's not something enforced by the language, but in my experience, taking a reference means by convention that you aren't going to store it – Antimony Aug 19 '12 at 21:07