This is a question about constructors. Two C++ classes A and B are related conceptually as
class A
{
B b;
};
class B
{
A *a;
};
The question is, when an instance of A is created, I want its member B to be constructed with a pointer to A. So it seems B requires a constructor that has a pointer to an instance of A as an argument, and that that constructor of B be invoked when an instance of A is constructed, rather than the default constructor of B.
Is there a simple way to do this?
Using struct here just for the public defaults.
struct A;
struct B {
B(A *a_ptr = 0) : a(a_ptr) {}
A *a;
};
struct A {
A() : b(this) {}
B b;
};
You might get a warning in the constructor for A from a busybody compiler that this points to an object that has not been fully constructed.
I have these structs.
struct V
{
int data[2];
V(int a,int b)
{
data[0] = a;
data[1] = b;
}
}
typedef std::vector<int> X;
struct A
{
B<V> member1;
B<X> member2;
A(V member1_, X member2_) : member1(member1_),member2(member2_){}
}
template<typename T>
struct B
{
T data;
B(T data_){data = data_;}
}
How do I create an object of struct A? I wish to declare an object A like so
A a;
and then use it later to assign member1 to it. This is because I would not know B's data until later in the program run. But the compiler would not let me and complains about default constructor in B, saying I don't have one. How do I write default constructors for B and A then while B is a template? Is there a better way to achieve this?
Thanks for your help.
Give struct B an empty default constructor. It will run the default constructor of data, too. You just need to make sure that T has a default constructor, too (actually, the current code of yours requires that, too - members are constructed before opening brace of constructor).
I know how to prevent dynamic instantiation of a class in C++. (Define my own 'new' operator) But is there a simple way to prevent static instantiation so that I force dynamic instances? That is, how do I do this... (This is not a derivable abstract base class. Just a simple class)
class B {
};
B b; // how do I prevent this without using friends or some derived class trick
B* b;
b = new B; // still want to be able to do this.
You can prevent it by making the c'tor private:
class B {
B() {}
public:
static B* alloc() { return new B; }
};
Instead of b = new B; you will do: b = B::alloc();
You can prevent it by making the c'tor private:class B { ...
}; Instead of b = new B; you will do: b = B::alloc();
But this is only half of the truth, right? I could still do an
static B* b = B::alloc();
yielding a pointer to a statically (i. e. created before execution of main()) object - i.e. this is more or less a static object, it only is located on the heap. Is there a way to prevent this?
I'm a PHP developer trying to write some C++.
I'm having trouble with assigning an object as an another object's property. In PHP, I'd write this:
class A {
public $b;
}
class B {
}
$a = new A;
$a->b = new B;
How do I do that in C++? I got this so far:
class A {
B b;
public:
void setB(&B);
};
class B {
};
void A::setB(B &b)
{
this->b = b;
};
A * a = new A();
B * b = new B();
a->setB(b);
What am I doing wrong?
Just do this:
class B
{
};
class A
{
B b;
};
int main()
{
A anA; // creates an A. With an internal member of type B called b.
// If you want a pointer (ie using new.
// Then put it in a smart pointer.
std::auto_ptr<A> aPtr = new A();
}
You don't actually need to create the B separately. The B b is part of the class and is created (using the default constructor) automatically when the A object is created. Creating the two objects seprately and then combining them is a bad idea.
If you want to pass some parameters to the B object as it is constructed. That is easy to do by creating a constructor for A that calls B's constructor:
class B
{
public:
B(std::string const& data) // The B type takes a string as it is constructed.
:myData(data) // Store the input data in a member variable.
{}
private:
std::string myData;
};
class A
{
public:
A(std::string const& bData) // parameter passed to A constructor
:b(bData); // Forward this parameter to `b` constructor (see above)
{}
private:
B b;
};
int main()
{
A a("Hi there"); // "Hi there" now stored in a.b.myData
}
Instead of &B, you mean B&.
class A {
B b;
public:
void setB(B&); //<--
};
A pointer cannot be implicitly dereferenced. So a->setB(b) won't compile. You need to write a->setB(*b).
You don't need new to construct an object. For example, this works:
A a;
B b;
a.setB(b);
Don't use idioms from other languages directly in C++. For example, setters and getters are seldom needed. In fact, your A class could just be a simple struct.
A couple changes will make it compile:
1. class B needs to be declared before A so that it can be used in class A
2. The declaration setB(&B) needs a minor change to setB(B&)
class B {
};
class A {
B b;
public:
void setB(B&);
};
void A::setB(B &b)
{
this->b = b;
};
int main ()
{
A * a = new A();
B * b = new B();
a->setB(*b);
}
To make it more efficient consider the adding the following constructor that accepts B as an argument and the initializes the member variable 'b'. This will use a copy constructor on the 'b' member variable instead of using the default constructor and then the assignment operator.
A(B& b_) : b(b_)
{
}
There are a lot of things wrong with this code:
As KennyTM notes, the ampersand is in the wrong place.
You are passing a B* to a function that takes a B&, they aren't the same in C++
The design shown in your php fragment appears to misdesigned. While what you are doing is something you might want to do at times, you'll usually want to use a constructor instead, C++ and PHP alike.
You are putting code directly in the file, this isn't allowed in C++, put it in the main function instead
memory management: you are using new without delete (or a smart pointer class)
You are using class B in class A while class A doesn't know about class B (it is defined later) - you should put class B on top (or perhaps use forward declaration)
A few ways to make your code work properly are shown below.
include <memory>
using std::auto_ptr;
class B
{
}
class A
{
public:
A();
SetB(B& b);
private:
B b1; // a B made in the constructor
B b2; // a COPY of the original B you make
}
A::A()
: b1(/*whatever you want to pass to B's constructor*/)
{
}
A::SetB(B& b)
{
b2 = b;
}
int main(int agrc, char** argv)
{
A firstA();
B firstB();
firstA.SetB(firstB);
A* secondA = new A();
B* secondB = new B();
secondA->SetB(*secondB);
auto_ptr<A> thirdA(new A());
auto_ptr<B> thirdB(new B());
thirdA->SetB(*thirdB);
// whatever other code
delete secondA;
delete secondB;
}
Note that id you call SetB only once (and there is no problem with cyclic depndencies between the different objects you are creating), but you do want the flexibility of constructing the B outside the class, you can instead make a parameter of the constructor.
Also note that you are making a copy of the B you create in main - if you want to use the came copy in the class (as you would in PHP), you should use a member reference (in which case you will need to set what it refers to in the constructor, you can't do so in the SetB function.
Then, note that there are serious problems with the secondA, secondB approach and as such it is not recommended (above nothing will go wrong, however, it is easy to get code that leaks memory this way (and hard to find out where the leak is) and on top of that when you want to use exceptions, you will need exception safe code, which is not achievable using plain old pointers.
Lastly, note that you mix and match here. There is no problem at all with using firstA and thirdB together, for example.
http://en.wikipedia.org/wiki/Diamond_problem
I know what it means, but what steps can I take to avoid it?
A practical example:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
Notice how class D inherits from both B & C. But both B & C inherit from A. That will result in 2 copies of the class A being included in the vtable.
To solve this, we need virtual inheritance. It's class A that needs to be virtually inherited. So, this will fix the issue:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
virtual inheritance. That's what it's there for.
I'd stick to using multiple inheritance of interfaces only. While multiple inheritance of classes is attractive sometimes, it can also be confusing and painful if you rely on it regularly.
Inheritance is a strong, strong weapon. Use it only when you really need it. In the past, diamond inheritance was a sign that I was going to far with classification, saying that a user is an "employee" but they are also a "widget listener", but also a ...
In these cases, it's easy to hit multiple inheritance issues.
I solved them by using composition and pointers back to the owner:
Before:
class Employee : public WidgetListener, public LectureAttendee
{
public:
Employee(int x, int y)
WidgetListener(x), LectureAttendee(y)
{}
};
After:
class Employee
{
public:
Employee(int x, int y)
: listener(this, x), attendee(this, y)
{}
WidgetListener listener;
LectureAttendee attendee;
};
Yes, access rights are different, but if you can get away with such an approach, without duplicating code, it's better because it's less powerful. (You can save the power for when you have no alternative.)
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
In this the attributes of Class A repeated twice in Class D which makes more memory usage... So to save memory we make a virtual attribute for all inherited attributes of class A which are stored in a Vtable.
Well, the great thing about the Dreaded Diamond is that it's an error when it occurs. The best way to avoid is to figure out your inheritance structure beforehand. For instance, one project I work on has Viewers and Editors. Editors are logical subclasses of Viewers, but since all Viewers are subclasses - TextViewer, ImageViewer, etc., Editor does not derive from Viewer, thus allowing the final TextEditor, ImageEditor classes to avoid the diamond.
In cases where the diamond is not avoidable, using virtual inheritance. The biggest caveat, however, with virtual bases, is that the constructor for the virtual base must be called by the most derived class, meaning that a class that derives virtually has no control over the constructor parameters. Also, the presence of a virtual base tends to incur a performance/space penalty on casting through the chain, though I don't believe there is much of a penalty for more beyond the first.
Plus, you can always use the diamond if you are explicit about which base you want to use. Sometimes it's the only way.
I would suggest a better class design. I'm sure there are some problems that are solved best through multiple inheritance, but check to see if there is another way first.
If not, use virtual functions/interfaces.
Use inheritance by delegation. Then both classes will point to a base A, but have to implement methods that redirect to A. It has the side effect of turning protected members of A into "private" members in B,C, and D, but now you don't need virtual, and you don't have a diamond.
This is all I have in my notes about this topic. I think this would help you.
The diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a member in A that B and C, and D does not override it, then which member does D inherit: that of B, or that of C?
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C {};
D d;
d.a = 10; //error: ambiguous request for 'a'
In the above example, both B & C inherit A, and they both have a single copy of A. However D inherits both B & C, therefore D has two copies of A, one from B and another from C. If we need to access the data member an of A through the object of D, we must specify the path from which the member will be accessed: whether it is from B or C because most compilers can’t differentiate between two copies of A in D.
There are 4 ways to avoid this ambiguity:
1- Using the scope resolution operator we can manually specify the path from which a data member will be accessed, but note that, still there are two copies (two separate subjects) of A in D, so there is still a problem.
d.B::a = 10; // OK
d.C::a = 100; // OK
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
2- Using static_cast we can specify which path the compiler can take to reach to data member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
static_cast<B&>(static_cast<D&>(d)).a = 10;
static_cast<C&>(static_cast<D&>(d)).a = 100;
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using overridden, the ambiguous class can overriden the member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C { int a; };
D d;
d.a = 10; // OK: D::a = 10
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using virtual inheritance, the problem is completely solved: If the inheritance from A to B and the inheritance from A to C are both marked "virtual", C++ takes special care to create only one A subobject,
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
D d;
d.a = 10; // OK: D has only one copy of A - D::a = 10
d.A::a = 20; // OK: D::a = 20
Note that "both" B and C have to be virtual, otherwise if one of them is non-virtual, D would have a virtual A subobject and another non-virtual A subobject, and ambiguity will be still taken place even if class D itself is virtual. For example, class D is ambiguous in all of the following:
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : virtual B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : virtual B, C {};