May an instance of a derived class be implicitly converted to an instance of its base class, when the only candidate constructor in the base class is marked explicit?
I ran this:
struct Base {
Base() {}
explicit Base(Base const& b) {}
};
struct Derived : Base {};
int main() {
Derived d;
Base b = d;
}
And got this:
error: no matching function for call to 'Base::Base(Derived&)'
Then I ran this:
struct Base {
Base() {}
Base(Base const& b) {}
};
struct Derived : Base {};
int main() {
Derived d;
Base b = d;
}
And got no errors.
But I'm not entirely convinced that this test succeeds due to explicitness rather than ctor synthesis. In particular, I didn't think that explicit cared about the type of arguments, but that it would force me to write Base b = static_cast<Base>(d) ... which I'm not doing in either case.
It's not the conversion that fails. Copy-initialization requires an accessible copy-constructor.
This also fails:
struct Base {
Base() {}
explicit Base(Base const& b) {}
};
int main() {
Base d;
Base b = d;
}
In hindsight, it seems clear.
The elements at play here are:
The only would-be-synthesised candidate constructor is Base(Base const&), and I don't provide a constructor Base(Derived const&).
Said constructor is explicit, but I provide no explicit conversion.
So, the answer is "no".
This:
int main() {
Derived d;
Base b = d;
}
is not upcasting. That is creating a new object, called b, which contains a copy of the value of d. In order to have upcasting, you must be using polymorphic values (references or pointers). Upcasting would therefore be:
int main() {
Derived d;
Base &b = d;
}
The variable b contains a reference to the Base part of d. If Base had some public member int baseValue;, then b.baseValue refers to the exact same data as d.baseValue. For example:
int main() {
Derived d;
Base &b = d;
d.baseValue = 10;
cout << b.baseValue << endl;
}
This will write 10. If b weren't a reference, but a regular object, it would have copied the (initialized) value from d before d's value was changed. And therefore changing one would not change the other.
The purpose of the explicit keyword is to prevent syntax like Base b = d from working. If you make a constructor explicit, you are saying, "I don't want the compiler to ever implicitly call this copy constructor. If the user is to use it, then they must explicitly say so." If you want implicit conversion of types, then you must say so.
Related
I was learning about inheritance in C++. So whenever a object of a class is created a constructor is called.
And constructor is used to initialize the class variables.
#include<bits/stdc++.h>
using namespace std;
class Base
{
protected:
int x;
public:
Base(int a): x(a)
{
cout<<"Base"<<endl;
}
};
class Derived: public Base
{
private:
int y;
public:
Derived(int b):y(b)
{
cout<<"Derived"<<endl;
}
void print()
{
cout<<x<<" "<<y<<endl;
}
};
int main()
{
Derived d(20);
d.print();
return 0;
}
Since here I am creating object of base class and calling print function on this. So I should get output.
But my code is giving compiler error, why?
Can anyone help me understanding this?
When you construct your Derived object in the Derived(int b): y(b) {}, the Base part of this object has to be constructed too. Since you do provide a constructor for Base which takes an int there won't be an implicitly defined default constructor in the Base (even if it was, the int data member x would have an undefined value). Thus, there's no way to construct the d in the Derived d(20) using your definitions for both classes.
You may look toward the following approach:
// Inside Base class:
// We provide a default constructor
// As well as one that takes an int
Base(int a = 0): x(a) {}
// Inside Derived class:
// We supply a value for the Base and a value for the Derived part
Derived(int b, int d): Base(b), y(d) {}
// Inside main():
Derived d(20, 30);
d.print();
// Prints: 20 30
When we have a default constructor provided for the Base, we can even do like so, and it will compile:
// Base part will be default constructed
Derived(int b): y(b) {}
// ...Prints: 0 20
Here, the Base part of a Derived instance will have a default value, while the Derived part will have a value explicitly supplied to it. In general, this would probably be a mistake, of logical nature. Nevertheless, it will compile.
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 wonder why people say:
"Inheriting class doesn't inherit the constructor".
If you could CAN use the parent class' constructor, and the parameterless constructor are called automatically no matter what.
Example:
#include <iostream>
using namespace std;
class A {
private :
int x;
public :
A () {
cout << "I anyway use parameter-less constructors, they are called always" << endl;
}
A (const int& x) {
this->x = x;
cout << "I can use the parent constructor" << endl;
}
};
class B : public A {
private :
int y;
public :
B() {
}
B (const int& x, const int& y) : A (x) {
this->y = y;
}
};
int main() {
B* b = new B(1,2);
B* b1 = new B();
return 0;
}
http://ideone.com/e.js/6jzkiP
So is it correct to 'say', constructors are inherited in c++ ? What is exact definition of "inherit" in programming languages ?
Thanks in advance.
I wonder why people say: "Inheriting class doesn't inherit the constructor".
Perhaps it is best to illustrate this with an example:
struct Foo
{
Foo(int, int) {}
};
struct Bar : Foo
{
};
What it means is that there is no Bar::Bar(int, int) constructor that you can call, despite the existence of a constructor with the same parameter list in the base class. So you cannot do this:
Bar b(42, 42);
In C++11, you can actually inherit constructors, but you must be explicit about it:
struct Bar : Foo
{
using Foo::Foo;
};
Now, you can say Bar b(42, 42);
What they mean is that constructor signatures are not inherited.
In your example, B does not have a constructor taking a single const int& even though its base class does. In this sense it has not "inherited" the constructor (but can still make use of it).
I think what they mean is:
struct A {
A(int, int) { }
};
struct B : public A {
};
int main()
{
A a(1, 2); // ok
B b(1, 2); // error
}
To compare with “non-special” member functions:
struct A {
void f() { }
};
struct B : public A {
};
int main()
{
A a;
B b;
a.f(); // ok
b.f(); // ok too
}
But of course, from within B you can call accessible A constructors (as automatically generated ones do). Ditto for the destructor.
Note that in C++11 you can use the “inheriting constructors” feature:
struct A {
A(int, int) { }
};
struct B : public A {
using A::A;
};
int main()
{
A a(1, 2); // ok
B b(1, 2); // ok now
}
A derived class can/must see base class constructors in order to invoke them, for consistency. However, their signature is not exposed in the derived class, hence, one cannot construct the class without an explicitly defined constructor, which forwards the required arguments to the base class constructor.
In C++11, one can inherit constructors: What is constructor inheritance?
Another approach to circumvent 'proxy constructors' in C++ < 11: How to define different types for the same class in C++
In your example, the default ("parameterless" as you say) constructor of B does invoke the default constructor of A, but this does not mean that B "inherited" that constructor, only that it "has access to" it. That is, A's default constructor is accessible from within B, yet it is not accessible from outside (no one can use A's default constructor from outside to construct an instance of B).
Another way to look at it is to ask, what is something frustrating about constructors and inheritance in C++? A common answer from some people (including myself) would be that there is no automatic facility which allows "pass-through" construction of base classes taking arguments from derived class constructors without explicitly declaring and defining the latter.
I have two versions of a C++ code. One give the problem and other does not:
/*
* This compiles fine
*/
class base {
private:
const char c;
};
int main() {
base b(); // compiles fine
}
/*
* This gives compilation error
*/
class base {
private:
const char c;
};
int main() {
base b; // error: structure 'b' with uninitialized const members
}
Note the difference is 'base b()' and 'base b'.
I thought that both will call default constructor and since the class has a const field, the program will fail to compile.
Please help to explain this.
That is because the first version does not create an object of type base, but rather declares a function called b which takes no argument and returns an object of type base:
base b; // Declares an object b of type base
base b(); // Declares a FUNCTION called b that takes no argument an returns a base
In fact, you could try the following to verify that this is indeed the case:
int main() {
base b(); // DECLARES function b()
b(); // INVOKES function b()
}
base b() // DEFINITION of function b()
{
base c;
// ...
return c;
}
Now function main() won't give you problems anymore, but the base c; inside the b() function will. Exactly like the base b; in your original example. Why?
Well, because in general data members whose type is const-qualified should be initialized as soon as you construct the object (just like data members of a reference type). A way to guarantee this in general is to initialize those data members in the constructor's initialization list.
This, for instance, will compile:
class base {
public:
base() : c('x') { }
private:
const char c;
};
int main() {
base b;
}
const char c; Must be defined when declared.
const char c = 'a'; for example
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.