I have a struct of Foo:
struct Foo
{
};
I have a struct of Bar:
struct Bar
{
};
They are handled by 2 more structs which maintain (add/remove) a pointer array of each:
struct FooContainer
{
Foo** FooList;
// add(), remove() etc
};
struct BarContainer
{
Bar** BarList;
// add(), remove() etc
};
Now, what I WANT is another struct called Baz which links (in a one-to-many fashion) Foo to Baz. I can't (for reasons not explained here) refer to them by index, it must be by pointer/reference.
Something like this:
struct Baz
{
Foo* foo;
Bar* bar;
};
If I wanted to add a constructor to Baz which took these non-const pointers, how would I do it?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
Do I pass the pointers into the constructor as const and then do something with them as I would if I were passing a reference to a struct? I then get issues with trying to set the value of a non-const pointer to a const pointer.
I hope this question makes sense...
Edit: Should I use reference instead of pointer?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
That is correct, you don't want to store constant pointers. However, it does not prevent you to store pointers to const, which is not the same thing.
This sounds confusing, so here is an illustration using your Baz example:
struct Baz
{
const Foo* foo;
const Bar* bar;
Baz(const Foo* newFoo, const Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(const Foo* newFoo) { foo = newFoo; }
void setBar(const Bar* newBar) { bar = newBar; }
};
everything is going to compile fine: it's Foo and Bar pointed to by foo and bar that are const, not the pointers themselves, which leaves you free to change the pointers as you wish.
This, on the other hand, is not going to compile:
struct Baz
{ // Note how const has moved to the other side of the asterisk
Foo* const foo;
Bar* const bar;
Baz(Foo* newFoo, Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(Foo* newFoo) { foo = newFoo; } // BROKEN!!!
void setBar(Bar* newBar) { bar = newBar; } // BROKEN!!!
};
Now the pointer, not the "pointee", is const, preventing you from changing foo or bar members.
Related
Given the following class:
class Foo
{
public:
//...
private:
Bar mBar;
};
Is it possible to expose the mBar member in such a way that it's members can be accessed, but not the mBar object itself?
The reason is that users should be able to access all of mBar's members but they should not be able to assign another Bar instance to mBar.
Bar has a lot of members and it would be cumbersome to write getters/setters and forwarding fuctions for them all. But if mBar is made public one is able to do aFoo.mBar = Bar(/*...*/);which is the only thing that should not be allowed.
Deleting Bar's assignment operators is not an option.
if you only want to protect against errors and not Machiavelli, operator-> might help (you might probably want a wrapper instead of directly put it in foo though):
class Foo
{
public:
//...
const Bar* operator ->() const { return &mBar; }
Bar* operator ->() { return &mBar; }
private:
Bar mBar;
};
so
Foo foo;
foo->bar_member;
foo.foo_member;
// Machiavelli
*foo.operator->() = Bar();
I would probably rethink your design but here is a possible indirect way using an intermediate get method:
struct Bar {
int intAttr;
};
class Foo {
Bar mBar;
public:
template <class U>
U& get(U Bar::* p) {
return mBar.*p;
}
};
This way, you can access any public member of mBar using:
Foo foo;
foo.get(&Bar::intAttr); // get
foo.get(&Bar::intAttr) = 0; // set
I've searched high and low for the answer for this, perhaps I'm just not using the right terms to get any results?
Is there any way to make it so that a member variable is const in that it can't be reassigned, and will always be the same object, but still allow the object itself to be modified? Much like the behavior of a const pointer to a non-const object, but without being an actual pointer?
The main use case that I see for this would be composition. Let's say Foo has-a Bar, and you want to be able to access and modify that Bar, but not change which Bar Foo has. Just change the properties/call non-const methods on that Bar. Is there any way to do this?
Not with const correctness machinery; it's too primitive for that (it's just a single bit: either "change" or "not change").
You can however mark assignment private and the container a friend so that only container methods will be allowed to assign, but mutators could be marked public for others to use.
class Foo {
public:
int x, y;
Foo() : x(0), y(0) {}
friend class Bar;
private:
Foo& operator=(const Foo& other){
...
return *this;
}
};
class Bar {
public:
Foo foo;
Bar(){
foo = Foo(); // OK from here
};
};
void baz() {
Bar bar;
bar.foo.x = 42; // Ok assigning a member of foo
bar.foo = Foo(); // Invalid from here (doesn't compile)
}
Normally you would just do
struct Foo {
Bar bar;
};
Each Foo object then has a Bar subobject, which is contained within Foo itself, and whose address does not change. Assigning to bar invokes Bar's assignment operator; it doesn't change the location of bar.
If you need polymorphic behaviour from the Bar, you would do
struct Foo {
const std::unique_ptr<Bar> bar;
};
Here, since the std::unique_ptr is const, it cannot be made to point to a different Bar object after Foo's initialization, but since the Bar itself is not const, it can be modified. You could also use const std::shared_ptr<Bar>.
My best guess is that you can make the member private and then use setter member functions that achieve the mechanics that you desire (i.e. the end user can only modify your member variables in the way that you want them to be modified).
I'm fairly new to C++, and I'm trying to understand the good practices for building classes.
Let's say I have a class Foo:
class Foo {
public:
double foo;
Foo(double foo);
Foo add(Foo f);
}
I want to make a class Bar, that is made of two Foo objects, and that creates a third one at construction.
1st option: Objects as class members
class Bar {
public:
Foo foo1;
Foo foo2;
Foo foo3;
Bar(const Foo &f1, const Foo &f2);
}
Bar::Bar(const Foo &f1, const Foo &f2):
{
foo1 = f1;
foo2 = f2;
foo3 = f1.add(f2);
}
As is, it does not work as I have not defined a default constructor for Foo.
2nd option: Pointers as class members
class Bar {
public:
const Foo* foo1;
const Foo* foo2;
const Foo* foo3;
Bar(const Foo &f1, const Foo &f2);
}
Bar::Bar(const Foo &f1, const Foo &f2):
{
foo1 = &f1;
foo2 = &f2;
foo3 = &(f1.add(f2));
}
Note: I have to declare foo1 and foo2 as const for the constructor to work.
It still fails though because for foo3 I am taking the address of a temporary result, which is illegal.
Which option is more natural (and how can I fix the errors)? I feel the first option is probably better, but then my Foo objects have to be created twice in memory, don't they? (once to call the constructor, and a second time by the constructor itself)
Any help appreciated.
It's fine to use pointers as members, but in your case you are simply working around a minor hiccup that really doesn't warrant the use of pointers, and using pointers can be dangerous as evidenced by an issue I'll point out shortly.
As is, it does not work as I have not defined a default constructor for Foo.
This is easily resolved by using initializers for Bar:
Bar(const Foo &f1, const Foo &f2) : foo1(f1), foo2(f2), foo3(f1.add(f2)) {}
as demonstrated here:
#include <iostream>
class Foo {
public:
double m_foo;
Foo(double foo) : m_foo(foo) {}
Foo add(Foo f) { f.m_foo += m_foo; return f; } // returns temporary!
};
class Bar {
public:
Foo m_foo1;
Foo m_foo2;
Foo m_foo3;
Bar(const Foo &foo1, const Foo &foo2);
};
Bar::Bar(const Foo &foo1, const Foo &foo2)
: m_foo1(foo1)
, m_foo2(foo2)
, m_foo3(m_foo1.add(m_foo2))
{
}
int main() {
Foo foo1(20.0);
Foo foo2(22.0);
Bar bar(foo1, foo2);
std::cout << bar.m_foo3.m_foo << "\n";
return 0;
}
Live demo: http://ideone.com/iaNzJv
In your pointer solution you introduce a glaring pointer problem: a pointer to a temporary.
foo3 = &(f1.add(f2));
f1.add returns a temporary Foo, which you take the address of, and then it goes away. This is a dangling pointer.
Your pointer implementation also doesn't explicitly take pointers as its inputs so f1 and f2 could run into the same problem:
Bar(Foo(20), Foo(22)); // two temporary Foos passed by reference
// but having their addresses taken. ouch.
If you're taking pointers, it's best to do that at the api to your class; you're going to have to care about the lifetime of the things pointed to, and try to make it easier for a caller to tell that you are doing so.
Bar(Foo* f1, Foo* f2);
But now if you're going to have F3 you're going to be responsible for managing it's memory:
Bar(Foo* f1, Foo* f2)
: foo1(f1), foo2(f3), foo3(new Foo(*f1.add(*f2)))
{}
~Bar()
{
delete f3;
}
So in your example case, using members is probably drastically better.
Save the use of pointers for large objects that you definitely don't want to copy, and where you can't use a move operation.
--- EDIT ---
The problem of conveying ownership of pointers has been largely solved in modern C++ (C++11 and higher), through "smart pointers", in particular std::unique_ptr and std::shared_ptr.
It is generally considered Best Practice to use these instead of raw pointers, although it requires learning some newer C++ concepts.
#include <memory>
struct Foo {};
class Bar {
public:
std::unique_ptr<Foo> m_f1; // we will own this
std::unique_ptr<Foo> m_f2; // and this
Bar(std::unique_ptr<Foo> f1) // caller must pass ownership
: m_f1(std::move(f1)) // assume ownership
, m_f2(std::make_unique<Foo>()) // create a new object
{}
~Bar()
{
// nothing to do here
}
};
int main() {
auto f = std::make_unique<Foo>();
Bar(std::move(f)); // the 'move' emphasizes that
// we're giving you ownership
// 'f' is now invalid.
return 0;
}
Live demo: http://ideone.com/9BtGkn
The elegance of this is that when Bar goes out of scope, the unique_ptrs will ensure that the objects they own are destroyed for us -- we don't have to remember to delete them.
In the above example, it would probably have been much better to make m_f2 a member rather than a pointer.
If the objects are not too expensive to pass around, I suggest using objects as members.
If you need to use pointers for some reason, you need to have ownership policies in place. Does Bar object own the objects? Does Bar just holds the pointers to the objects but is not responsible for releasing resources used by them?
If Bar owns the Foo objects, prefer to use one of the smart pointers. You'll need to make copies of those objects by using new and hold on to those pointers.
Here's how I see it:
class Bar {
public:
std::unique_ptr<Foo> foo1;
std::unique_ptr<Foo> foo2;
std::unique_ptr<Foo> foo3;
Bar(const Foo &f1, const Foo &f2) : foo1(new Foo(f1)), ... {}
};
std::unique_ptr does not have a copy constructor. Hence, you must provide a copy constructor for Bar and initialize its members from the copy appropriately.
If Bar does not own the Foo objects, you might be able to get by using references as member data.
class Bar {
public:
Foo const& foo1;
Foo const& foo2;
Foo const& foo3;
Bar(const Foo &f1, const Foo &f2) : foo1(f1), ... {}
};
I think it is nonsense that the object is the same as a primitive variable.
class Foo {
public:
double _stocks;
Business* _business;
Foo(double stocks, Business* business):_stocks(stocks), _business(business){}
Foo* add(const Foo& f) {
_stocks += f._stocks;
_busines->merge(f._business);
return this;
}
virtual ~Foo() { delete _business; }
}
class Bar {
public:
Foo* _foo1;
Foo* _foosub;
// Foo* _foo3;
Bar(Foo* f1, Foo* f2); // unable const for f1 at least
}
Bar::Bar(Foo* f1, Foo* f2):
{
_foo1 = f1;
_foosub = f2;
_foo1.add(*f2);
// _foo3 is the same as _foo1
}
void main() {
Foo company1(100.00, BusinessFactory.create("car"));
Foo company2(2000.00, BusinessFactory.create("food"));
Bar conglomerate(&company1, &company2);
// to be continued
}
I have a structure like this, with struct Baz inheriting from 2 different structs, Foo and Bar.
I have 2 methods called the same thing, one with a parameter of Foo and one with a parameter of Baz.
struct Foo
{
};
struct Bar
{
};
struct Baz : Foo, Bar
{
virtual void something(const Foo& foo)
{
};
virtual void something(const Bar& bar)
{
};
};
I call it like this
Baz baz;
baz.something(baz);
And understandably I have an issue with my code knowing which function I am calling if I pass it an instance of Baz. I get “Ambiguous call to overloaded function”.
I know I can cast my Baz to Foo or Bar to resolve the issue...
Baz baz;
baz.something((Bar)baz);
...but is there another way of dealing with this design issue?
I want to call the Foo method ONLY if the object being passed is not of type Bar.
edit:
If this was C# (which it isn't) I could probably solve this using a template where clause.
First off, note that the cast you've used would create a temporary object. You probably meant this:
baz.something(static_cast<Bar&>(baz));
And to answer your question, it should be possible to use SFINAE for this:
struct Baz : Foo, Bar
{
virtual void something(const Bar &bar)
{ /* ... */ }
template <
class T,
class = typename std::enable_if<
std::is_convertible<const T&, const Foo&>::value &&
!std::is_convertible<const T&, const Bar&>::value
>::type
>
void something (const T &foo)
{ something_impl(static_cast<const Foo&>(foo)); }
private:
virtual void something_impl(const Foo &foo)
{ /* ... */ }
};
Live example
For example, I have two classes
class Foo;
class Bar;
class Foo {
const Bar &m_bar;
...
};
class Bar {
const Foo &m_foo;
...
};
Let foo is object of Foo and bar is object of Bar. Is there any way (normal or "hacking") to create/initialize foo and bar that their members m_bar and m_foo would referenced to each other (I mean foo.m_bar is bar and bar.m_foo is 'foo')?
It is allowed to add any members to Foo and Bar, to add parents for them, to make they templates and so on.
What is the linkage of foo and bar? If they have external
linkage, you can write something like:
extern Foo foo;
extern Bar bar;
Foo foo( bar );
Bar bar( foo );
(I'm assuming here that it is the constructors which set the
reference to a parameter.)
This supposes namespace scope and static lifetime, of course
(but an anonymous namespace is fine).
If they are class members, there's no problem either:
class Together
{
Foo foo;
Bar bar;
public:
Together() : foo( bar ), bar( foo ) {}
};
If they're local variables (no binding), I don't think there's
a solution.
EDIT:
Actually, the local variables have a simple solution: just
define a local class which has them as members, and use it.
This can't work if i understand your Problem correctly, since to create an Object Bar you need Foo and vice versa.
You must not use References but an Pointer instead. Where you can create both Objects separatley and then set Bar to Foo and Foo to Bar.
class Foo
{
public:
Foo();
void setBar( const Bar* bar ){ _bar = bar; }
private:
const Bar* _bar;
}
// class Bar analog to Foo
void xxx:something(void)
{
Foo* f = new Foo;
Bar* b = nee Bar;
f->setBar(b);
b->setBar(f);
...
}