I can't compile the following code using g++ 4.1.2:
#include <memory>
class A
{
public:
};
std::auto_ptr<A> GetA()
{
return std::auto_ptr<A>(new A);
}
class B
{
B(std::auto_ptr<A>& pA)
{
}
};
class C : public B
{
C() : B(GetA())
{
}
};
I get:
invalid cast of an rvalue expression of type std::auto_ptr<A> to type std::auto_ptr<A>&
The problem is I can't define a variable and pass its reference because I am inside a initialization list.
How can I do that when I am only allowed to change class C?
If you can only change C, you could do something like:
class C: public B
{
explicit C(std::auto_ptr<A>& pA) : B(pA) {}
public:
static C *GetC()
{
std::auto_ptr<A> pA = GetA();
return new C(pA);
}
};
The problem is trying to bind a non-const reference to the temporary returned by GetA. If you can assign that to a variable first, you have an lvalue and it works ok.
As Alex B says said (deleted answer), if you can change B, it would be better to take that auto_ptr argument by value; and if you can change compiler, it would be better to use unique_ptr and move semantics instead.
Depends on what B does with the passed in reference.
If B is going to take a copy of the argument, then make the argument a const &
If B is going to hold a reference to the argument then you need whatever is passed in to have a longer lifetime than the instantiation of B. (As mentioned already, the temporary created by a call to GetA() doesn't.)
Related
This question already has answers here:
Why can I call a non-const member function pointer from a const method?
(5 answers)
Closed 3 years ago.
Imagine the following example:
class A
{
public:
void doSomeStuff() { std::cout << "SomeStuff" << std::endl; }
};
class B
{
public:
B(A& a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A &a;
};
If doSomeStuff() would change the data, wouldn't that affect class B as well? Why is such behaviour allowed?
If doSomeStuff() would change the data, wouldn't that affect class B as well?
Well, not in the way a compiler checks for const correctness. A B holds a reference to an A. That object can reside anywhere, but most importantly it doesn't reside inside the B object. So modifying it does not do something with undefined behavior like changing a const object. We have a reference to a non-const object, so it's possible to modify the object via the reference. That's as far as the C++ type system cares, whether or not the object is maybe physically const.
It will probably affect the logical state of the B, but it is the responsibility of the programmer to ensure the class invariants hold. C++ will not hold your hand in that endeavor.
The original object of the class A will be changed.
When you are using a const member function then the function deals with const T *this where T is the class type.
That is data members of the object are considered constant.
For a referenced type it could look like
A & const a;
However references themselves can not be constant.
That is for example this declaration
int x;
int & const rx = x;
is invalid and does not mean the same as
const int & rx = x;
So the class B has a reference that points to a non-constant object and using the reference the object can be changed.
Compare with the following declaration of the class B
class B
{
public:
B(A * a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A *a;
};
Then then a constant member function is used the data member is considered like
A * const a;
(pointers themselves may be constant) that is the pointer itself that is constant not the object pointed to by the pointer and you can not change the pointer itself but you can change the object pointed to by the pointer.
The const-qualified this pointer that's present in a const-method protects data changes from members inside B. B holds a reference to A so the object a references does not reside inside B and thus changes are allowed. This const qualification of this does not pass on to the reference.
If you would want to avoid that, you're supposed to make the reference to the helper class const:
class B
{
public:
B(const A& a) : a(a) {}
void constStuff() const { /* Invalid call: a.doSomeStuff(); */ }
private:
const A &a;
};
Consider this example:
class C {};
class B {
public:
B(C& c) : c_(c) {};
private:
C& c_;
};
class A {
public:
A(C& c) : b(c) {};
private:
B& b;
};
A has a reference member b of class B. B has a constructor that takes a reference of class C. A's constructor takes a reference of class C and tries to initialize b by calling the latter's constructor with c.
But clang complains with the following message:
wtf.cpp:12:13: error: non-const lvalue reference to type 'B' cannot bind to a value of unrelated type 'C'
A(C& c) : b(c) {};
^ ~
1 error generated.
It sounds almost as if clang thought I was assigning c to b, but my intent is to call B's constructor with c. What am I doing wrong here?
What you describe is not restricted to initializer lists, but to the usual construction of references. The following should not compile:
class C
{};
class B
{
public:
B(C& c)
: c_(c)
{}
private:
C& c_;
};
int main()
{
C c;
B b0(c); // This works because you actually create an object of type B.
B& b1(c); // Error, cannot construct reference to B from C.
B& b2 = c; // Same as above, only a different notation.
// You cannot write a constructor of B to make these lines work,
// because you do not create an object of type B.
}
An object of class B can be constructed from a reference to a C object, but the same does not hold for references. A reference can only be created from an object of the same type, or a type below in inheritance hierarchy.
That is exactly the point of a reference: You do not construct an object. You just introduce a new name for an object that was created somewhere else.
You cannot do that. A reference is in fact close to non modifiable pointer. That means that a B& can only reference a object of class B or of a sub-class of B. And there is nothing like the construction of a reference.
You could construct a temporary B object from the C reference, but you cannot initialize a reference with a temporary object, because as soon as the reference will have be initialized, the referenced object would be destroyed.
So you must store a real object an not a ref in A:
class A {
public:
A(C& c) : b(c) {};
private:
B b;
};
I'd like to assign the object of type B to object of type A, but i don't know why it works with different types for the assignment?
#include <stdio.h>
class B
{
public:
B()
{
printf("B default constructor.\n");
}
};
class A
{
public:
A()
{
printf("A Default constructor.\n");
}
A(B const& b) // if add the tag "explicit" for the constructor, it will not work...
{
printf("User constructor.\n");
}
A(const A& a)
{
printf("copy-constructor.\n");
}
void get(){printf("A::get\n");}
};
int main()
{
A a = B(); // What's the meaning to assign object of type B to object of type A?
Why it works with above line?
How it works when do this?
a.get();
}
Every constructor that can be called with a single argument defines an implicit conversion to a class type. So the constructor:
A(B const& b)
is a conversion constructor. If this type of conversion is not useful, you've found the answer: declaring it as explicit can prevent it:
explicit A(B const& b)
I think your problem comes from thinking it is assignment. But A a = B(); is initialization. a is not first created with default constructor and then assigned to, it is directly constructed. And while I don't have the standard reference handy, if you don't have the constructor but have the assignment operator overload, that line will not compile, because it is not assignemnt, it needs the right constructor. To have assignment, try
A a;
a = B(); // actually assigns A(B()) implicitly if no operator= overload
If all data members of a class can be assigned, then objects of the class can be assigned, so that's why a = A(); works without adding any code.
If you want to block the implicit conversion, make the constructor explicit (example in the other answer).
I have a class C that can be converted to class A and a function that takes an A* as an argument. I want to call it with a C*, but I can't seem to get a conversion constructor to work. I get: error: cannot convert ‘C*’ to ‘A*’ for argument ‘1’ to ‘void doSomething(A*)’. What am I doing wrong?
class C {
};
class A {
public:
A(C* obj) {}
};
void doSomething(A* object);
int main()
{
C* object = new C();
doSomething(object);
}
Conversion constructors can only be defined for user defined types, in your case A. However, they do not apply to fundamental types as pointers like A*.
If doSomething was taking an A const& instead (or simply an A), then the conversion constructor would be invoked as you expect.
If you main requirement is to be able to call the existing doSomething function, then you can do this:
int main()
{
C* object = new C();
A a(object);
doSomething(&a);
// May need to delete object here -- depends on ownership semantics.
}
You probably mean that you want C to be a subclass of A:
class C : public A {
...
};
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.