For some class C:
C* a = new C();
C* b(a); //what does it do?
C* b = a; //is there a difference?
C* b(a) and C* b = a are equivalent. As with many languages, there's more than one way to do it...
Note that in
C* a = new C();
C* b(a);
b is a pointer to a C object assigned the same value as a. However,
#include "somefile.h"
C* b(a);
we could just as easily be defining b as a function which takes an object of type a, and returns a pointer to C.
The standard describes the different kinds of initialization is 8.5, and these two specifically under 8.5/12.
C* b(a); //what does it do?
This is called direct initialization. If 'b' had class type, then the compiler would perform overload resolution on the constructors in C using 'a' as an argument. For a pointer type, it simply initializes 'b' with 'a'.
C* b = a; //is there a difference?
The standard does consider these to be different in some cases, the above syntax is called copy initialization. As for direct initialization as 'b' is not a class type, then it is initialized with the value of 'a'. If 'a' and 'b' are the same class type, then direct initialization is used.
Where 'b' is a class type and 'a' has a different type (class or not) then the rules are slightly different (8.5/14-b1.b3). So for the following code:
C b = a;
Firstly, an attempt is made to convert 'a' to type 'C' and then this temporary object is used to initialize 'b'. This is significant as you can have a situation where direct initialization succeeds but copy initialization fails:
class A {
public:
operator int ();
};
class B {
public:
B (int);
};
void foo ()
{
A a;
B b1 (a); // Succeeds
B b2 = a; // Fails
}
C* a = new C(); Now it is creating a pointer of
type C, which also allocate new
memory by using new keyword....
Following statement is depend upon
your constructor logic. C*
b(a); //what does it do?
Your first and third statement are
equivalent. C* b = a; //is there a
difference?
The first one creates a new instance of C and puts its address in a.
The second one is a pointer-to-function declaration. This pointer can point to any function taking an argument of type a and returns a pointer to an object of type C.
The third one declares b, a pointer to an object of type C and initializes it with a.
Related
I have two classes with similar structure.
class A{
int a;
char *b;
float c;
A(char *str) { //allocate mem and assign to b }
};
class B{
int a;
char *b;
float c;
B(char *str) { //allocate mem and assign to b }
B(B & bref) { //properly copies all the data }
};
I want to copy an object of B to the object of A. Are the following conversions fine?
A aobj("aobjstr");
B bobj("bobjstr");
bobj = aobj; //case 1
bobj = B(aobj); //case 2
Will the case 2 work? Will aobj be properly converted and interpreted as B & when B's copy constructor gets called?
EDIT: What about?
B bobj(aobj)
No, you can't implicitly convert between unrelated types without writing conversion constructors or conversion operators. Presumably, your compiler told you this; mine gave errors such as:
error: no match for ‘operator=’ in ‘bobj = aobj’
note: no known conversion for argument 1 from ‘A’ to ‘const B&’
error: no matching function for call to ‘B::B(A&)’
You could allow the conversion by giving B a conversion constructor:
class B {
// ...
B(A const & a) { /* properly copy the data */ }
};
If you can't change the classes, then you'll need a non-member function to do the conversion; but this is probably only possible if the class members are public. In your example, all the members, including the constructors, are private, so the classes can't be used at all. Presumably, that's not the case in your real code.
If you want to live dangerously, you might be able to get away with explicitly reinterpreting an A object as a B, since they are both standard-layout types with the same data members:
// DANGER: this will break if the layout of either class changes
bobj = reinterpret_cast<B const &>(a);
Note that, since your class allocates memory, it presumably needs to deallocate it in its destructor; and to avoid double deletions, you'll also have to correctly implement both a copy constructor and a copy-assignment operator per the Rule of Three.
If that all sounds like too much work, why not use std::string, which takes care of memory management for you?
If you tried to compile it you would find that none of this works. For one thing your constructors are private.
bobj = aobj; //case 1
This tries to call an assignment operator with the signature:
B& B::operator =(A const&)
This does not exist and compilation will fail.
bobj = B(aobj); //case 2
This tries to call A::operator B(), which does not exist and compilation will fail.
Finally:
B bobj(aobj)
This tries to call a constructor with the signature B::B(A const&), which does not exist and compilation will fail.
You say,
I can't change/modify class A and B, those are generated.
Then either the generator needs to be fixed or you're going to have to write your own adaptors.
You can do this by considering the following notes:
1) char* b makes a problem. When you copy aobj to bobj, the value of pointer aobj.b will be copied to bobj.b which means that they both refer to a same memory location and changing one like this: aobj.b[0] = 'Z' will cause bobj.b to change.
You can solve this by changing b from a pointer to a flat array:
//...
char b[MAXLEN];
//...
The better solution to this is to define a constructor (accepting the other type) and overload the assignment (=) operator, at least for class B, and handle the pointer assignment (allocate buffer for the new pointer and copy content to it).
2) UPDATED: A sample syntax is like this:
bobj = B(reinterpret_cast<B&> (aobj));
// or simply:
bobj = reinterpret_cast<B&> (aobj);
3) Note that this is dangerous, not safe, and not recommended. This means that the design of your solution should probably change. For example, A and B may both inherit from a common base class; B inherits from A; or B explicitly defines a constructor and an assignment operator for class A. These are far more recommended.
class B;
class A{
B *b;
public:
void operator= (B *b){
this->b = b;
}
};
B *b = new B()
A *a = new A();
a = b;
I get a "cannot convert B* to A*" error.
Is there a way around this?
Now, if there is a way, and if I use something like:
a = NULL;
Which operator "=" would be used?
You have assigned the pointer instead of the object. Simply replace the last instruction with:
*a = b;
To answer the second question: NULL can be defined in more than one way in the compiler (as of the latest standard, either as the integral 0 or the literal nullptr). Pointers can also be cast to pointer of other types, but passing a void* to an overloaded function that takes an int* or a long* may make the compiler unable to resolve the function being called.
If however, you want to avoid NULL, simply make operator(B& b) instead. References are sure to be pointing at an object.
Your operator= provides assignment from a B* to an A. Your code does not provide a conversion from a B* to a A* (as the error message shows). As such, a=NULL will not use the assignment operator you provided, since a is a pointer, not an A. Your code allows assignment from a B* to an A, like A a= new B();.
If you meant to be using actual objects instead of pointers, remove all the * from your code:
class B{};
class A{
B b;
public:
void operator= (const B& b){ //pass non-primitives by const reference
this->b = b;
}
};
B b;
A a;
a = b;
If you wanted to be using pointers, the only "useful" way to assign a B* to an A* is if a B object derives from A. That appears to not be what you're doing, so assigning a B* to an A* would make no sense in your code.
Change your statement that assigns to a to:
*a = b;
Can somebody explain why when c finishes construction, the destructor of b (member of c) is called, while d is destructed - as expected - when c's destructor is called ?
#include <iostream>
using namespace std;
class A
{
public:
int a, b;
};
class B
{
public:
A* array[10];
B()
{
for(int i = 0 ; i < 10 ; i++)
array[i] = new A();
}
~B()
{
for(int i = 0 ; i < 10 ; i++)
delete array[i];
}
};
class C
{
public:
B b;
B* d;
C()
{
b = B();
}
~C()
{
delete d;
}
};
int main()
{
B b = B();
C c = C();
cout << "Ashlamish" << endl;
system("pause");
return 0;
}
In b = B() you're constucting a new temporarty instance of class B, assigning a copy to b, then the temporary instance is descructed.
Because in the constructor of C, you are creating a temporary B object in the line c = B(); and when the assignment is complete, that temporary object is being destroyed.
I think you want to declare c like this:
C c;
This will construct an object named c which will be destructed on scope exit.
On the other hand, what you have;
C c = C();
will construct an anonymous object of type C, copy construct c with it and immediately destruct the anonymous object. c will still be destructed at the end of the scope.
In the constructor of C you have
b = B();
what this does is:
construct temporary object of type B
assign this object to b by the use of default assignment operator
destroy the temporary object
To fix this use initialization list in the constructor of C like this:
C() : b()
{ }
or just leave the constructor empty, that way it will use the default constructor.
The line b = B(); in C constructor instantiates a new object of type B, and uses B's copy constructor to copy such object in C::b.
When C constructor returns b doesn't get destroyed, but the B temporary object used to call b's copy constructor is.
You could just remove such instruction in order to avoid instantiation of a B temporary, in this case b will just be constructed using the default constructor.
destructor of temporary B is called (b = B();), not of member b. this line can be removed at all because b is already default constructed in implicit initialization list
You have committed here a cardinal sin - not obeying the rule of 3.
Your B needs a destructor but does not implement copying and assignment.
You then go ahead and compound the error by actually doing an assignment.
You also go on to delete an uninitialised pointer. (It would be fine if d were NULL but there is no reason why it should be).
You also need to implement copy-construction, especially as your compiler may well choose to use it for the above constructs, although it probably won't actually do so.
can somebody please help me with an error
conversion from `A' to non-scalar type `B' requested
I have class A and derived from it B, but I have problems with these rows:
A a(1);
A *pb = new B(a);
B b = *pb; //here I have an error
thanks in advance for any help
class A {
protected:
int player;
public:
A(int initPlayer = 0);
A(const A&);
A& operator=(const A&);
virtual ~A(){};
virtual void foo();
void foo() const;
operator int();
};
class B: public A {
public:
B(int initPlayer): A(initPlayer){};
~B(){};
virtual void foo();
};
edited
I have this code and (I can't change it):
A a(1);
A *pb = new B(a);
B b = *pb;
I tried to create constructor for B:
B::B(const A & a):
player(a.player){}
B& B::operator=(const A& a){
if(this == &a){
return *this;
}
player = a.player;
return *this;
}
but it gives me an error, really need help from professionals
Your problem is due to static type checking. When you have this line:
A *pb = new B(a);
The static type of pb is A * and it's dynamic type is B *. While the dynamic type is correct, the compiler is checking the static type.
For this simple code, since you know the dynamic type of pb is always a B, you can fix this with a static cast:
B b = *static_cast<B *>(pb);
But be warned that if the dynamic type of pb was an A * the cast would cause undefined behavior.
When you dereference an 'A' pointer, you get an 'A' even if it points to a 'B'. Polymorphism does not come into play here! To preserve the 'B' properties to the 'A' object you should properly cast the initialization as explained in some of the other answers.
In such situations a dynamic cast is most appropriate. Dynamic cast will invoke the runtime type system to figure out the "real" type of bp and will return 0 if it can't be cast to the requested type. As you know the real type you could also use static_cast here but generally this isn't the case in such situations.
B* b = dynamic_cast<B*>(pb);
*pb will give you a A& and not a B&. It's just like pb being an A* and not a B* even though the actual object is a B.
B b = *pb will attempt to copy-construct a B using a synthesised copy constructor. The copy constructor will therefore be looking for a B& as its argument. You have no constructor to make a B from an A, hence the error.
As #R Samuel Klatchko says you could just cast it or, in the case you've given, you could just make pb actually be a B*.
You are trying to assign an object of type A to object of type B. Which is not allowed unless you define a type cast operator. pb is a pointer to A object and in general it is not a pointer to B (in your case it is, but it doesn't matter for the compiler, since it's declared as pointer to A). To make such assignement possible, you first need to down-cast pb to pointer of B (as R Samuel Klatchko pointed out, in your case static_cast is perfectly fine; in other cases you might need use dynamic_cast).
I have a question about C++, how to assign a Base object to a Derived object? or how to assign a pointer to a Base object to a pointer to a Derived object?
In the code below, the two lines are wrong. How to correct that?
#include <iostream>
using namespace std;
class A{
public:
int a;
};
class B:public A{
public:
int b;
};
int main(){
A a;
B b;
b = a; //what happend?
cout << b.b << endl;
B* b2;
b2 = &a; // what happened?
cout << b->b << endl;
}
It makes no sense to assign a base object to a derived (or a base pointer to a derived pointer), so C++ will do its best to stop you doing it. The exception is when the base pointer really points at a derived, in which case you can use dynamic cast:
base * p = new derived;
derived * d = dynamic_cast <derived *>( p );
In this case, if p actually pointed at a base, the pointer d would contain NULL.
When an object is on the stack, you can only really assign objects of the same type to one another. They can be converted through overloaded cast operators or overloaded assignment operators, but you're specifying a conversion at that point. The compiler can't do such conversions itself.
A a;
B b;
b = a;
In this case, you're trying to assigning an A to a B, but A isn't a B, so it doesn't work.
A a;
B b;
a = b;
This does work, after a fashion, but it probably won't be what you expect. You just sliced your B. B is an A, so the assignment can take place, but because it's on the stack, it's just going to assign the parts of b which are part of A to a. So, what you get is an A. It's not a B in spite of the fact that you assigned from a B.
If you really want to be assigning objects of one type to another, they need to be pointers.
A* pa = NULL;
B* pb = new B;
pa = pb;
This works. pa now points to pb, so it's still a B. If you have virtual functions on A and B overrides them, then when you call them on pa, they'll call the B version (non-virtual ones will still call the A version).
A* pa = new A;
B* pb = pa;
This doesn't work. pa doesn't point B, so you can't assign it to pb which must point to a B. Just because a B is an A doesn't mean than an A is a B.
A a;
B* pb = &a;
This doesn't work for the same reason as the previous one. It just so happens that the A is on the stack this time instead of the heap.
A* pa;
B b;
pa = &b;
This does work. b is a B which is an A, so A can point to it. Virtual functions will call the B versions and non-virtual ones will call the A versions.
So, basically, A* can point to B's because B is an A. B* can't point to A because it isn't a B.
The compiler won't allow that kind of thing. And even if you manage to do it through some casting hack, doing so makes no sense. Assigning a derived object to a pointer of a base makes sense because everything that base can do, derived can do. However, if the opposite case was allowed, what if you try to access a member defined in derived on a base object? You would be trying to access an area of memory filled with garbage or irrelevant data.
b = a; //what happend?
This is plain illegal - A is not B, so you can't do it.
b2 = &a; // what happened?
Same here.
In neither case, the compiler wouldn't know what to assign to int b, hence he prevents you from doing that. The other way around (assigning Derived to Base) works, because Base is a subset of Derived.
Now if you would tell us, what exactly you want to achieve, we might help you.
If it's a case of assigning an A that is known to be a Derived type, you can do a cast:
A* a = new B();
B* b = dynamic_cast<B>(a);
Just remember that if a is not a B then dynamic_cast will return NULL. Note that this method works only on pointers for a reason.
Derived object is a kind of Base object, not the other way around.