I was looking to create a function that is capable of working with any Derived Object of A.
However in this example, I can't seem to be able to use B Object in a function that has a A Typing on it. Is there any way I pass B into the Function?
class A {
public:
A() {
}
};
class B :A {
public:
B() {
}
};
void function(A a) {
return;
}
int main(void) {
B b();
function(b);
}
I've commented on the fixes needed inline:
class A {
public:
A() {}
};
class B : public A { // public inheritance or A will be an inaccessible base of B
public:
B() {}
};
void function(const A& a) { // take a reference to an A to avoid copy-slicing
// ... work with the A part of the object you reference with `a`
}
int main() { // void not needed (but not an error as such)
B b; // not a function declaration anymore
function(b);
}
Actually you are lucky. You made two mistakes that caused passing b to the function fail, while in fact without that other mistakes you can pass b to the function but it would do the wrong thing silently.
First the two mistakes: B b(); declares a function. To declare a default constructed B you write B b;. Then B inherits privately, hence you cannot convert a B to an A. Thats what the error your code causes have told you.
However, after fixing those (and removing user declared constructors taht shouldnt be there when they do nothing)...
class A {};
class B : public A {};
void function(A a) {}
int main(void) {
B b;
function(b); // object slicing !!
}
This code compiles without errors, but usually it does the wrong thing!
Any B can be converted to an A because the inheritance is public, but what happens is object slicing: What is object slicing?. If B had any members not in A then they would all be lost when passing it to function. Its not an issue here because neither A nor B have any members, but in general you want to avoid objects to get sliced.
TL;DR: References / pointers are needed for polymorphism. Pass by (const) reference:
void function(const A& a) {} // does not modify a
void function(A& a) {} // modifies a
Related
I have two classes which represent two different data types that can be converted back and forth. I want to have a constructor for each which takes an object of the other type so that I can more easily convert between the two, like so:
class A{
public:
A(B n){
//Do stuff converting n to type A
}
};
class B{
public:
B(A n){
//Do stuff converting n to type B
}
};
But it always fails to compile.
If you pass B by reference, you can use it as an incomplete type in A, with a forward declaration, like:
class B; // forward declaration
class A {
public:
A() = default;
A(B& n); // declare it here
};
class B {
public:
B() = default;
B(A n) {
//Do stuff converting n to type B
}
};
A::A(B& n) // define it here, B is fully visible now
{
//Do stuff converting n to type A
}
int main()
{
A a;
B b(a);
A another(b);
}
Note that you'd also need default constructors for at least A or B, as otherwise you cannot create an A without a B or the other way around. We also only declared the constructor in A, but defined it after B is fully visible (thanks #MattMcNabb for the comment). In this way, you'd be able to use any member of B in the constructor, since at that point B is fully visible.
The problem you are having is a common for beginners of C++ (or C for that matter).
The issue is that the signature A(B n) is seen by the compiler before the declaration of B is seen. But clearly, you cannot put B before A in the code, or you'd end up with the same type of situation.
This can be solved using forward declarations and references. My suggested default approach to this would be to declare these two entities as
class B;
class A {
public:
A(const B& n) {
// Do stuff converting n to type A
}
};
class B {
public:
B(const A& n) {
// Do stuff converting n to type B
}
};
First, sorry for thw poor title... I don't really know how to express with one
sentance what I mean... You are weclome to edit the title.
I have three classes A, B and C.
class A{
public:
A(double a):a_(a){}
private:
double a_;
}
class B{
public
B():a_ptr_(NULL){}
B(A const& a):a_ptr_(new A(a)){}
~B(){ delete a_ptr_; }
void set(A const& a){ a_ptr_ = new A(a); }
private:
A* a_ptr_;
}
class C{
public
C():a_ptr_(NULL){}
C(A const& a):a_ptr_(&a){}
void set(A const& a){ a_ptr_ = &a; }
private:
A* a_ptr_;
}
My problem is that if I do
B b(A(1.0));
C c(A(1.0));
the class A is instanciated twice for B (two creation constructor calls).
C::a_ptr_ is problematic. If I do :
B b;
C C;
{
A a(1.0);
b.set(a);
c.set(a);
}
I have the same problems outside the brackets.
I would like to find a way to store a pointer on A in B or C without
copying the class A too many times and without having undefined pointers.
I've found something with a move constructor but I've never used such.
Any idea ? Thx !
std::shared_ptr is exactly what you need. This class is used for storing one pointer in different places. The target object will be deleted after the last shared_ptr pointing to it is destroyed. Since you are clearing the memory in the destructor, your classes obtain ownership of the A object. You can use something like this:
class B{
public
B():a_ptr_(NULL){}
B(A * a): a_ptr_(a){ }
~B(){}//don't need to do anything here.
void set(A * a){ a_ptr_.reset(a); }
private:
std::shared_ptr<A> a_ptr_;
}
<...>
class C should be written in a similar manner
<...>
A * a = new a(1.0);
B b(a);
C c(a)
Now, if you want to make a constructor or set method that takes a by reference, you will not be able to avoid copying it. Also, in this case you can't safely take the address of this variable.
I have the following situation:
class B
{
public:
void methodInB();
};
class C
{
public:
void methodInC();
};
class A
{
public:
void methodInA();
private:
B objB;
C objC;
};
void A::methodInA()
{
objB.methodInB();
}
int main()
{
A objA;
objA.methodInA();
return 0;
}
I want to be able to call C::methodInC() from within B::methodInB(), but I'm not sure what the way to go about it would be (not without messing with globals).
My first idea was to add a C* pC pointer as a member of B, and then from methodInB() call it as pC->methodInC. This would require I set the pointer from within A before using the method (possibly in A's constructor). My problem is I may need to call other objects from within B if I add a D and E objects, and I don't want to fill the class definition with pointers.
Is there some other way of doing this? An implicit reference to the object the object belongs to? Kind of like this but for the parent? So I could at least do parent->objC->methodInC()?
I think the cleanest way would be to "inject the dependency", that is, to pass objC to methodInB, which would then invoke methodInC on that object:
void A::methodInA()
{
objB.methodInB(objC);
}
// ...
void B::methodInB(C &objC)
{
objC.methodInC();
}
Let every class B, C, D, E, etc. have a pointer to the A object of which they are subobjects.
class A;
class C;
class B
{
A* pA;
void MethodB();
};
...
void B::MethodB
{
(pa->CObject).MethodC();
}
I have the code:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test() says "class A", but how I can call method getString() from class B and not A?
Thanks!
The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this
A a;
what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!
To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.
Since a pointer example was already shown by #Nawaz, I will give another using a reference:
class C{
public:
C() : a(b) { // references must be initialized in the constructor initializer list
}
std::string test() {return a.getString();}
private:
B b; // moved to class scope to ensure that it stays alive
A& a;
};
You need to implement like this:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
This will call getString() from class B and not A.
What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).
Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.
You are slicing therefore it will not work. a is an A it is not a B.
To work your class member variable a must be a pointer or a reference.
As a pointer
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
As a reference
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
Of course the code I have produced leaks but will work with the virtual function.
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.