C++ Complete Reference says ,"Except for the = operator,operator functions are inherited by a derive class."
But i cannt understand the behaviour of the following code:
#include<iostream>
using namespace std;
int main(){
class b{
int i;
public:
int operator=(b parm){
cout<<"base overload";
};
};
class d: public b{
int j;
public:
};
b inst1,inst11;
d inst2,inst22;
int a;
inst1=inst11; //works because assignment operator is overloaded for b
inst2=inst22; //If =operator function is not inherited then why does it output "base oberload"
inst1=inst2; //works because assignment overloaded for b
// inst2=inst11; //But if b was inherited then this should also work but it doesnt
}
I am expecting two output statements "base overload" but it is outputting three Why?? this is driving me nuts
operator= is not inherited. But the compiler will generate implicitly an operator= for class d, which invokes b::operator= for the assignment of the base subobject.
the operator performs member-wise copy assignment of the object's bases and non-static members, in their initialization order, using built-in assignment for the scalars and copy assignment operator for class types.
then
inst2=inst22; //If =operator function is not inherited then why does it output "base oberload"
The generated d::operator= is called here; inside which b::operator= is invoked.
inst1=inst2; //works because assignment overloaded for b
b::operator= is called here, it expects b as the argument and inst2 could be implicitly converted to the base class b.
// inst2=inst11; //But if b was inherited then this should also work but it doesnt
d::operator= is tried to be called here, it expects d as the argument but inst11 can't be implicitly converted to the derived class d.
Related
I am trying to learn about C++ inheritance, but one thing doesn't make any sense to me.
Everything a googled about what is not inherited by a derived class said that the constructors, friends, and operator= are not inherited. However, this information doesn't fit with the results of my program.
I did an example of inheritance and the result is what follows:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "constructor base class without parameters" << endl;
}
Base(int a)
{
cout << "constructor base class with int parameter" << endl;
}
Base(const Base& b)
{
cout << "copy constructor base class" << endl;
}
Base& operator= (const Base& base)
{
cout << "operator= base class" << endl;
}
};
class Derived: public Base
{
};
int main()
{
Derived d;
cout << endl << "here 1" << endl << endl;
Derived d2 = d;
cout << endl << "here 2" << endl << endl;
d = d2;
//Derived d3 (3); // ERROR!!
}
The output was:
constructor base class without parameters
here 1
copy constructor base class
here 2
operator= base class
If all the constructors and operator= are not inherited, why were operator=, default constructor and copy constructor of the base class called?
Dervied has no constructors, in this case a default constructor is generated which calls the default constructor of all base classes and members.
Similar things happen with the copy constructor and assignment operator. The Base class versions are being called by automatically generated Derived class versions.
This has nothing to do with inheritance of constructors or assignment operators.
Classes don't automatically inherit constructors, although you can force them to provide a base class's constructors with a using statement:
class Derived: public Base
{
public:
// Force this class to provide the base class's constructors
using Base::Base;
// Force this class to provide the base class's assignment operator
using Base::operator=;
};
The copy constructor wasn't inherited either. Instead, the compiler automatically generated a copy constructor for the derived class. If all of a class's member variables and base classes are copyable, then the class itself is copyable, and it'll generate the copy constructor automatically.
The same rules apply to the assignment operator: if all of a class's members provide a copy assignment operator, the compiler automatically generates one for the class itself.
Copy/move constructor is the exception according to the standard.
Referring to the standard:
For each non-template constructor in the candidate set of inherited
constructors other than a constructor having no parameters or a
copy/move constructor having a single parameter, a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class.
PS. Base& operator = (const Base& base)is not a constructor. It is assignment. So it works like any other member function. Since it is public in your example, it got inherited.
#include<iostream>
using namespace std;
class A
{
public:
A(){ cout <<"1";}
A(const A &obj){cout <<"2";}
};
class B: virtual A
{
public:
B(){cout <<"3";}
B(const B & obj):A(obj){cout<<"4";}
};
class C: virtual A
{
public:
C(){cout<<"5";}
C(const C & obj):A(obj){cout <<"6";}
};
class D:B,C
{
public:
D(){cout<<"7";}
D(const D & obj):C(obj),B(obj){cout <<"8";}
};
int main()
{
D d1;
D d(d1);
}
I am getting 13571468 as output. But I think that output should be 13572468. Why normal constructor is running instead on of copy constructor of class A?
Your code makes a copy of an instance of D, invoking its copy constructor.
Your class D's copy constructor only invokes the copy constructors of its C and B's superclasses. Because it does not invoke A's copy constructor, it gets default-constructed.
Virtually-inherited classes can be thought of as direct superclasses of the most-derived class. That's what virtual inheritance means. As such, in your instance of D, its virtually-inherited A is a direct superclass of D, and not of B or C; as such, B and C's invocations of A copy-constructor is not invoked.
When you have a virtually-inherited class, all your constructors really have two versions created "behind the scenes": one that's responsible for constructing any virtually-inherited classes, and one that's not. The one that's not does not call the virtually-inherited classes's constructors.
Example:
class C
{
public:
void operator =(int i) {}
};
class SubC : public C
{
};
The following gives compilation error:
SubC subC;
subC = 0;
"no match for 'operator=' in 'subC = 0'"
Some sources state that it is because assignment operators are not inherited. But isn't it simply because default constructed copy-assignment of SubC overshadows them?
The copy assignment operator is automatically generated in the derived class. This causes the base class's assignment operator to be hidden due to the regular name hiding rules of C++. You can unhide the name in the base class through the "using" directive. For example:
class C
{
public:
void operator =(int i) {}
};
class SubC : public C
{
public:
using C::operator=;
};
A copy assignment operator for a base class does not have the signature required for a copy assignment operator for a derived class. It is inherited by the derived class, but does not constitute a copy assignment operator in it. So even though assignment operators are inherited, just like other member functions, it does not provide copy assignment.
I haven't done it, but according to The Man Himself (Stroustrup) it's a feature of C++11 to do it with constructors, but it's been in since C++98 to do it with other methods.
This is DIRECTLY lifted from the link:
People sometimes are confused about the fact that ordinary scope rules
apply to class members. In particular, a member of a base class is not
in the same scope as a member of a derived class:
struct B {
void f(double);
};
struct D : B {
void f(int);
};
B b; b.f(4.5); // fine
D d; d.f(4.5); // surprise: calls f(int) with argument 4
In C++98, we can "lift" a set of overloaded functions from a base
class into a derived class:
struct B {
void f(double);
};
struct D : B {
using B::f; // bring all f()s from B into scope
void f(int); // add a new f()
};
B b; b.f(4.5); // fine
D d; d.f(4.5); // fine: calls D::f(double) which is B::f(double)
So there ya go. You can probably "take it if you want it" even before C++11, though I haven't tried it myself.
Except copy-assignment operator, other overloaded operator can be inherited.
I agree the opinion that default constructed copy-assignment of SubC overshadows overloaded assignment operator of C.
If SubC don't provide a copy-assignment operator, Compiler would synthese a copy-assignment operation,
as follow:
class SubC : public C
{
public:
SubC & operator=( const SubC & other );
}
then the 'SubC & operator=( const SubC & other )' overshadows assignment operator of C,
results in compile error.
If
SubC other;
SubC subC;
subC = other;
then, this case, compile ok.
I always think I know C++ pretty well, but sometimes I'm surprised by even the most fundamental things.
In the following scenario, I'm confused as to why the constructor Derived::Derived(const Base&) is invoked:
class Base
{ };
class Derived : public Base
{
public:
Derived() { }
Derived(const Base& b)
{
std::cout << "Called Derived::Derived(const Base& b)" << std::endl;
}
};
int main()
{
Derived d;
Base b;
d = b;
}
This outputs: Called Derived::Derived(const Base& b), indicating that the second constructor in Derived was invoked. Now, I thought I knew C++ pretty well, but I can't figure out why that constructor would be invoked. I understand the whole "rule of four" concept, and I would think that the expression d = b would do one of two things: Either it would 1) invoke the implicit (compiler-generated) assignment operator of Base, or 2) Trigger a compiler error complaining that the function Derived& operator = (const Base&) does not exist.
Instead, it called a constructor, even though the expression d = b is an assignment expression.
So why does this happen?
d = b can happen because b is converted to Derived.
The second constructor is used for automatic type conversion.
It's like d = (Derived) b
Derived isa Base, but Base isn'ta Derived, so it has to be converted before assignment.
assigning base to derived? perhaps you meant (a) by ref (b) or derived to base. This doesn't really make sense, but the compiler is correctly using your (non-explicit) constructor to convert the Base instance to a new Derived instance (which is subsequently assigned into d).
Use an explicut constructor to prevent this from happening automatically.
Personally I think you messed up your code sample, because, normally assigning firstclass base to derived makes no sense without a conversion
There are two interacting features at play here:
Assignment Operators are never inherited
A constructor that is not explicit, or a conversion operator (operator T()) define a user-conversion that can be used implicitly as part of a conversion sequence
Assignement Operators are never inherited
A simple code example:
struct Base {}; // implicitly declares operator=(Base const&);
struct Derived: Base {}; // implicitly declares operator=(Derived const&);
int main() {
Derived d;
Base b;
d = b; // fails
}
From ideone:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: no match for ‘operator=’ in ‘d = b’
prog.cpp:2: note: candidates are: Derived& Derived::operator=(const Derived&)
Conversion sequence
Whenever there is an "impedance" mismatch, such as here:
Derived::operator= expects a Derived const& argument
a Base& is provided
the compiler will try to establish a conversion sequence to bridge the gap. Such a conversion sequence may contain at most one user-defined conversion.
Here, it will look for:
any constructor of Derived that can be invoked with a Base& (not explicit)
a conversion operator in Base that would yield a Derived item
There is no Base::operator Derived() but there is a Derived::Derived(Base const&) constructor.
Therefore our conversion sequence is defined for us:
Base&
Base const& (trivial)
Derived (using Derived::Derived(Base const&))
Derived const& (temporary object bound to a const reference)
And then Derived::operator(Derived const&) is called.
In action
If we augment the code with some more traces, we can see it in action.
#include <iostream>
struct Base {}; // implicitly declares Base& operator(Base const&);
struct Derived: Base {
Derived() {}
Derived(Base const&) { std::cout << "Derived::Derived(Base const&)\n"; }
Derived& operator=(Derived const&) {
std::cout << "Derived::operator=(Derived const&)\n";
return *this;
}
};
int main() {
Derived d;
Base b;
d = b;
}
Which outputs:
Derived::Derived(Base const&)
Derived::operator=(Derived const&)
Note: Preventing this ?
It is possible, in C++, to remove a constructor for being used in conversion sequences. To do so, one need to prefix the declaration of the constructor using the explicit keyword.
In C++0x, it becomes possible to use this keyword on conversion operators (operator T()) as well.
If here we use explicit before Derived::Derived(Base const&) then the code becomes ill-formed and should be rejected by the compiler.
Since you've defined a constructor for Derived which takes type Base and you are down-casting Base, the compiler chooses the most suitable constructor for the upcast, which in this case is the Dervied(const Base& b) you've defined. If you did not define this constructor you would actually get a compiling error when trying to make the assignment. For more info, you can read the following at Linuxtopia.
It can't assign value of different type, so it should first construct a Derived temporary.
class A {};
class B { public: B (A a) {} };
A a;
B b=a;
I read this from http://www.cplusplus.com/doc/tutorial/typecasting/ . It says this is a implicit type conversion. From class A to class B.
I want to ask, is this also an example of copy constructor?
Thanks.
No, it's not a copy constructor. A copy constructor copies one object of one type into another of the same type:
B::B(const B& b)
{
// ...
}
As a side note, if you need a copy constructor then you also need a destructor and an assignment operator, and probably a swap function.
What B::B(A) is is a conversion function. It's a constructor that allows you to convert an object of type A into an object of type B.
void f(const B& obj);
void g()
{
A obja;
B objb = obja;
f(obja);
}
No, A copy constructor has the form
class A
{
public:
A(const A& in) {...}
}
No, a copy constructor is called when you create a new variable from an object. What you have there is two objects of different types.
The line B b = a; implies that a copy constructor is used, as if you had typed B b = B(a); or B b((B(a)));. That is, the compiler will check whether B has an accessible (public) copy constructor - whether user-defined or the default one provided by the compiler. It doesn't mean, though, that the copy constructor has to be actually called, because the language allows compilers to optimize away redundant calls to constructors.
By adding a user-defined copy constructor to B and making it inaccessible, the same code should produce a compiler error:
class A {};
class B {
public:
B (A ) {}
private:
B (const B&) {} // <- this is the copy constructor
};
A a;
B b=a;
For example, Comeau says:
"ComeauTest.c", line 10: error: "B::B(const B &)" (declared at line 6), required
for copy that was eliminated, is inaccessible
B b=a;
^