C++ inherited operator not being called in the derived class - c++

I have following code in C++
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class A{
public:
int x;
int y;
int first(){
return x;
}
int second(){
return y;
}
};
class C{
public:
float a,b;
C(){
a = 0.0f;
b = 0.0f;
}
template<class T>
C(T t){
cout<<"Copy Constructor\n";
a = t.first();
b = t.second();
}
template<class T>
C & operator=(T const &c){
cout <<"Assignment operator\n";
this->a = c.first();
this->b = c.first();
}
};
class D: public C{
public:
template <typename T> D (T t) : C(t) {}
float area(){
return a*b;
}
};
int main(){
A a;
a.x = 6;
a.y = 8;
C c(a);
D d(a);
D e = a; // Here copy constructor is being called!!
cout<<e.a<<" "<<e.b<<" "<<e.area()<<endl;
}
Here is the output of the above program
Copy Constructor
Copy Constructor
Copy Constructor
6 8 48
Why is assignment operator not being called in derived class?
Edit1 : I have changed the question to make the question more clear.

Constructors are not inherited as regular public functions. Default constructor are defined by the compiler if missing, but you should define a constructor taking an A parameter (or templated as you did for C) for D. You will need an assignment operator to be defined as well.
class D: public C{
public:
D(A aparam)
: a(aparam.first(), b(aparam.second()){
}
D& operator=(const D& rhs){
a = rhs.first();
b = rhs.second();
}
float area(){
return a*b;
}
};

You can grab back said operator= explicitly using :
using C::operator=
in D class.
operator= are inherited but masked by default by th eone generated by th ecompiler.

Related

Is the assignment operator inherited or not?

I know that the assignment operator is not inherited by derived classes, instead the compiler will create a default one if it is not redeclared. But I do not understand why the output of the following code snippet is Base operator=:
#include <iostream>
using namespace std;
class B {
protected:
int h;
public:
B& operator=(const B& ob){
if (this!=&ob) {
h = ob.h;
cout << "Base operator=\n";
}
return *this;
}
};
class D: public B {
protected:
float r;
public:
};
int main() {
D a, b;
a = b;
return 0;
}
Doesn't that mean that when calling a = b the base B& operator=(const B& ob, so isn't it inherited? Where am I wrong ?
The generated assignment is "all the base assignments, in order of inheritance declaration", so your generated assignment is essentially
D& operator=(const D& d)
{
B::operator=(d);
return *this;
}
If you were to derive from both B and C - in that order; class D: B, C - it would be equivalent to
D& operator=(const D& d)
{
B::operator=(d);
C::operator=(d);
return *this;
}
That is, the assignment is not inherited, but it's used.
With the expression a = b, the compiler generated assignment operator for D calls the user-defined assignment operator in B.
Yes you are correct that assignment operators are not inherited.

using-declaration for friend function

In C++11 it is possible to make a public member of a private base class accessible to the outside (public) with a using declaration. For example
class A {
private:
int i = 2;
public:
void f() { i = 3; }
friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};
class B : private A {
public:
using A::f;
};
int main() {
B b, b2;
b.f();
}
b.f() is possible because of the using A::f in the definition of B.
Is it possible write a similar declaration which would make the up-cast from B& to A& possible for the friend function operator==(A&, A&), so that b == b2 can be called in main()?
No, only B can internally cast itself to A, and it otherwise is not possible because from a client's perspective B is not an A but rather has an A
Even if you replaced your friend bool operator= with a member function equals:
class A {
private:
int i = 2;
public:
void f() { i = 3; }
bool equals(const A& r){return i == r.i;}
};
class B : private A {
public:
using A::f;
using A::equals;
};
While this compiles, you cannot ever call b.equals(b2) because no implicit conversion is ever possible from a type of B to a type of A from the caller's perspective (due to private inheritance) .
You'll need to provide your own operator== or change your inheritance to public or protected. Here's an example where B declares its own friend bool operator==
class B : private A {
public:
using A::f;
friend bool operator==(const B& l, const B& r)
{
return (static_cast<A>(l) == static_cast<A>(r)) && true;
// "true" is a stand-in for some other condition
}
};
Read more at isocpp
Edit:
If you really want to play games, you will notice that I said no implicit conversion is ever possible, but some explicit conversions are. Because B does technically derive from A you can do pointer casting to make it work, but I don't recommend it:
class A {
private:
int i = 2;
public:
void f() { i = 3; }
bool equals(const A* r){return i == r->i;}
};
class B : private A {
public:
using A::f;
using A::equals;
};
int main() {
B b, b2;
b.f();
(::A*)(&b)->equals((::A*)(&b2));
}
Or you could use pointer casting's ugly cousin, reference casting, if you wish to keep the original operator== syntax
class A {
private:
int i = 2;
public:
void f() { i = 3; }
friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};
class B : private A {
public:
using A::f;
};
int main() {
B b, b2;
b.f();
((::A&)(b)) == ((::A&)(b2));
}
See ยง11.2 [class.access.base] for more

Passing member function (or workaround)

I want to do the following:
class A{
private:
//some data
B b;
double f(double);
public:
A(){
b = new B(f); // does not work of course
}
};
class B{
public:
B(double (*func)(double));
};
Class B is supposed to solve a mathematical problem specified by the function func. Class A should now use B to solve this problem for func=f. The member function f accesses the private data members of A.
The problem is, of course that I cannot simply pass a pointer to member function. I know there are ways to do that, but B should still be able to take any function, not only members of A.
Until now, I just made f and the members of A static, but I think this is a rather bad design. Can you think of any workaround for this?
You can use the standard std::function<> template as a polymorphic wrapper for your functions.
Your class B simply store an instance of std::function<double (double)> and call it through foo :
class B
{
public:
B(const std::function<double (double)>& func) : func(func) {}
void foo(double d)
{
std::cout << func(d);
}
private:
std::function<double (double)> func;
};
While your class A build its B member with one of its member function (f), thanks to std::bind :
class A
{
public:
double md;
B b;
double f(double d) const
{
return md * d;
}
public:
A(double d) : md(d), b(std::bind(&A::f, this, std::placeholders::_1)) { }
};
We can now simply use it :
int main() {
A a(42);
a.b.foo(2); // Output : 84
}
Live demo here.
How about using polymorphism as an alternative to your current design?
For example:
class A
{
protected:
virtual double f(double x) = 0;
};
class B1 : public A
{
public:
double f(double x) {return x+1.0;}
};
class B2 : public A
{
public:
double f(double x) {return x+2.0;}
};
...
A* arr[4];
arr[0] = new B1;
arr[1] = new B2;
arr[2] = new B1;
arr[3] = new B2;
for (int i=0; i<4; i++)
cout << arr[i]->f(0.0);
This a fully working program for your sample.
#include <memory>
#include <iostream>
#include <functional>
class B
{
public:
B(std::function<double(double)> func)
{
std::cout<<func(1.0);
}
};
class A
{
private:
std::unique_ptr<B> b;
double f(double)
{
std::cout<<"A::f";
return 2.0;
}
public:
A() : b(new B(std::bind(&A::f, this, std::placeholders::_1)))
{
}
};
int main()
{
A a;
}
Please note you don't destroy b there and also keep in mind you are passing this to B, thing that might be dangerous (B might be alive after A is destroyed and if you use this inside f... boom!).
I would also suggest avoiding pointers and if this is not possible using std::unique_ptr
EDIT: And a version without b as pointer, std::function and std::bind
#include <iostream>
class A;
class B
{
public:
B(A* obj, double(A::*func)(double))
{
std::cout<<(obj->*func)(1.0);
}
};
class A
{
private:
B b;
double f(double)
{
std::cout<<"A::f";
return 2.0;
}
public:
A():b(this, &A::f)
{
}
};
int main()
{
A a;
}
Since function f() is not static it's type is "double ( A::* )(double)", not "double (*)(double)".
However for this particular case it is better re-design.
Does really A consist of data and instance of problem solver (class B), or A consist of data and delegates some operations to B?
Does really class B need some to know about methods from class A, or it expects data in some format?
class DataType {};
class ResultType {};
class A
{
DataType data;
DataType preprocess(Data d) {/*...*/}
ResultType process() { return B::compute(data); }
bool isSolvable() { return B::solve(preprocess(data)); }
};
class B
{
public:
ResultType compute(DataType);
bool solve(DataType);
};
Possible solution:
class A
{
B* b;
static double f(double d); //static change function type form `double(A::*)(double)` to `double(*)(double)`
public:
A()
{
b = new B(f);
}
}
only drawback that f cant take any data form A or B.

How does the abstract base class avoid the partial assignment?

As is talked about in Item 33 in "More Effective C++", the assignment problem is
//Animal is a concrete class
Lizard:public Animal{};
Chicken:public Animal{};
Animal* pa=new Lizard('a');
Animal* pb=new Lizard('b');
*pa=*pb;//partial assignment
However, if I define Animal as an abstract base class, we can also compile and run the sentence:*pa=*pb. Partial assignment problem is still there.
See my example:
#include <iostream>
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
};
Ab::~Ab(){}
class C:public Ab{
private:
int a;
double b;
};
class D:public Ab{
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
Do I miss something? Then what's the real meaning of the abstract base class?
I got the answer by myself. I missed a code snippet in the book.
Use protected operator= in the base class to avoid *pa=*pb. Use abstract base class to avoid animal1=animal2.Then the only allowed expressions are lizard1=lizard2;chicken1=chicken2;
See the code below:
#include <iostream>
class Ab{
private:
int a;
double b;
public:
virtual ~Ab()=0;
protected: //!!!!This is the point
Ab& operator=(const Ab&){...}
};
Ab::~Ab(){}
class C:public Ab{
public:
C& operator=(const C&){...}
private:
int a;
double b;
};
class D:public Ab{
public:
D& operator=(const D&){...}
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
The abstract base class cannot help in case of assignment because the base sub-object is not instantiated (what an abstract class would block) but is sliced off the derived object (i.e. the assignment is done between already existing base sub-objects).
To avoid the problem the only solution I can think to is
make the assignment virtual
check in the assignment that the source instance is of the correct type
In code
#include <iostream>
struct Base {
int bx;
Base(int bx) : bx(bx) {}
virtual Base& operator=(const Base& other) {
bx = other.bx;
return *this;
}
};
struct A : Base {
int x;
A(int bx, int x) : Base(bx), x(x) {}
A& operator=(const Base& other) {
const A& other_a = dynamic_cast<const A&>(other);
Base::operator=(other);
x = other_a.x;
return *this;
}
};
struct B : Base {
int x;
B(int bx, int x) : Base(bx), x(x) {}
B& operator=(const Base& other) {
const B& other_b = dynamic_cast<const B&>(other);
Base::operator=(other);
x = other_b.x;
return *this;
}
};
The dynamic_cast<const A&>(other) is the operation that will fail if the object passed to the assignment operator is not of the correct derived type (it can be a sub-derived object, but this should be logically ok for an assignment source).
As an example:
int main(int argc, const char *argv[]) {
Base *pa1 = new A(1, 2);
Base *pa2 = new A(3, 4);
Base *pb1 = new B(5, 6);
Base *pb2 = new B(7, 8);
*pa1 = *pa2; std::cout << pa1->bx << "/" << dynamic_cast<A*>(pa1)->x << "\n";
*pb1 = *pb2; std::cout << pb1->bx << "/" << dynamic_cast<B*>(pb1)->x << "\n";
std::cout << "Ok so far\n";
*pa1 = *pb1; // Runtime error here (bad cast)
return 0;
}
It doesn't matter that your base class has pure virtual functions because you haven't defined the operator= for any of the classes. So when the compiler sees this statement:
*pc=*pd;
where pc and pd are both of type Ab, it will call the default assignment operator for Ab, which will result in partial assignment. As in the following example, I get the output as "Abstract Base" which is from abstract base class:
class A {
public:
virtual void foo() =0;
virtual A& operator=(const A& rhs) {
std::cout << "Abstract Base";
return *this;
}
};
class B : public A {
public:
virtual void foo() {
std::cout << "b:foo";
}
};
class C : public A {
public:
virtual void foo() {
std::cout << "c:foo";
}
};
int main()
{
A* b = new B();
A* c = new C();
*b = *c;
return 0;
}
Since you have not handled the assignment operators in your classes, you land up in situation partial assignment as Scot clearly describes in his article.
You need to handle assignments in your classes. In current design default implicit assignment operator of Ab is called and thus all the properties of children class are lost.
To avoid this you should have an implementation like this:
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
virtual Ab& operator=(const Ab& rhs){cout<<"in Ab="<<endl;}
};
Ab::~Ab(){}
class C:public Ab{
C& operator=(const Ab& rhs){cout<<"in C="<<endl;
return operator=(dynamic_cast<const C&>(rhs)); }
C& operator=(const C& rhs){
cout<<"do somethin in C="<<endl;
}
private:
int a;
double b;
};
class D:public Ab{
D& operator=(const Ab& rhs){cout<<"in D="<<endl;
return operator=(dynamic_cast<const D&>(rhs)); }
D& operator=(const D& rhs){
cout<<"do somethin in D="<<endl;
}
private:
int a;
double b;
};

does assignment operator work with different types of objects?

class A {
public:
void operator=(const B &in);
private:
int a;
};
class B {
private:
int c;
}
sorry. there happened an error. is assignment operator valid ? or is there any way to achieve this? [There is no relation between A and B class.]
void A::operator=(const B& in)
{
a = in.c;
}
Thanks a lot.
Yes you can do so.
#include <iostream>
using namespace std;
class B {
public:
B() : y(1) {}
int getY() const { return y; }
private:
int y;
};
class A {
public:
A() : x(0) {}
void operator=(const B &in) {
x = in.getY();
}
void display() { cout << x << endl; }
private:
int x;
};
int main() {
A a;
B b;
a = b;
a.display();
}
This isn't an answer, but one should be aware that the typical idiom for the assignment operator is to have it return a reference to the object type (rather than void) and to return (*this) at the end. This way, you can chain the assignent, as in a = b = c:
A& operator=(const A& other)
{
// manage any deep copy issues here
return *this;
}
Both assignment operator and parameterized constructors can have parameters of any type and use these parameters' values any way they want to initialize the object.
Others have clued in on this, but I'll actually state it. Yes you can use different types, but note that unless you use friend, your class cannot access the private members of the class it's being passed in with the operator.
Meaning A wouldn't be able to access B::c because it's private.