Inherited operator= not working? - c++

I am overloading operator= on a struct EqualTestBase, and operator= takes different parameters than are used to construct the struct.
struct EqualTestBase
{
EqualTestBase(int one) {}
EqualTestBase& operator=(std::string two)
{
//stuff
return *this;
}
};
It works fine on the base class. But a trival struct derived from it, EqualTestDerived, acts like it doesn't have the operator= member function.
struct EqualTestDerived : public EqualTestBase
{
EqualTestDerived(int one) : EqualTestBase(one) {}
};
void test()
{
EqualTestBase basetest(0);
basetest = "test"; //this is fine, compiles
EqualTestDerived derivedtest(0);
derivedtest = "test"; //this does not compile, says there is no constructor that takes type const char[5]
}
Do I have to redefine operator= on all derived structs, or is there a way to automatically pass down that functionality?

The derived class has an implicitly-declared copy-assignment operator, which hides the one declared in the base class. You can use using to bring it into scope:
struct EqualTestDerived : public EqualTestBase
{
EqualTestDerived(int one) : EqualTestBase(one) {}
using EqualTestBase::operator=;
};

operator= isn't inherited. If a class doesn't define operator= itself, the compiler will synthesize one for it (regardless of the fact that its base class does define an operator=).
If you want something that can be inherited (and can be virtual) you generally want to define it as a function with a different name. The generally accepted name for such a function is clone (though clone is normally more like a copy constructor, creating a new instance of an object, not just assigning to an existing one).

Related

Avoid copying all constructors in subclasses

So a base class has multiple constructors:
sf::Sprite()
sf::Sprite(const Texture& texture)
sf::Sprite(const Texture& texture, const IntRect& rectangle)
And I'm subclassing this class multiple times:
class Sub : public sf::Sprite {
public:
Sub() : sf::Sprite() {};
Sub(const Texture& texture) : sf::Sprite(texture) {};
Sub(const Texture& texture, const IntRect& rectangle) : sf::Sprite(texture, rectangle) {};
// My subclass specific code
};
As you see, I have to repeat these three constructors for every subclass. Is there a way to avoid this, since the constructors usually don't do anything special? Sometimes I need some class specific initialization though, so it's not always viable to just straight out copy everything.
You can accomplish this by inheriting constructors (since C++11).
If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.
e.g.
class Sub : public sf::Sprite {
public:
using sf::Sprite::Sprite;
// My subclass specific code
};
If the inherited constructors is used to initialize a Sub, the sf::Sprite subobject is initialized using the inherited constructor, and all other members of Sub are initialized as if by the defaulted default constructor.
If there're some special cases need to be processed, you still can define constructor(s) in Sub, the inherited constructor with the same signature will be hidden.
As with using-declarations for any other non-static member functions, if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived.
You can use the using keyword to inherit the constructor of your base class, excluding the special ones (default, copy, move). To shorten your default constructor simply use = default. If you want class specific initialization you can simply write the constructor again, just as you do now.
class Sub : public sf::Sprite {
public:
Sub() = default;
using sf::Sprite::Sprite;
Sub(const Texture& texture)
{
// your custom code.
};
// My subclass specific code
};
If you can just 'inherit' the constructor, i.e. have one with exactly the same arguments, simply use using as explained in the other answers. However, if your derived class's constructor has additional arguments and/or requires some class specific initialization, you may use a variadic template.
struct base
{
base(int);
base(std::string const&);
base(some_type const&);
base(std::string const&, some_type const&);
/* ... */
};
struct derived : base
{
template<typename...Args>
derived(some_other_type const&x, Args&&...args)
: base(std::forward<Args>(args)...)
, private_datum(x)
{
construction_details(); // class-specific initialisation
}
private:
some_other_type private_datum;
void construction_details(); // implemented in source code
};

Explicit operator= call (T::operator=)

I am reading qt sources and I've seen a code like this many times:
buttonOpt.QStyleOption::operator=(*opt);
So, I guess it is something like buttonOpt = *opt but why do they use this syntax instead of default and user-friendly? Is this faster or any other profit exists?
This is because they are explicitly calling the operator= from the base class of buttonOpt, which is QStyleOption.
buttonOpt.QStyleOption::operator=(*opt);
//similar behavior
class Base
{
public:
virtual bool operator<(Base & other)
{
std::cout << "Base";
}
};
class Derived : public Base
{
public:
bool operator<(Base & other) override
{
std::cout << "Derived";
}
};
int main()
{
Derived a;
Derived b;
a < b; //prints "Derived"
a.Base::operator <(b); //prints "Base"
}
The code you show is explicitly calling the base class assignment, i.e. only the base class parts of the QStyleOptionButton get assigned, but not the member variables of the object.
It appears from the documentation, that no operator= is declared for QStyleOptionButton, so if one would call the usual assignment on such an object, the compiler would try to generate such an operator, consisting of the assignment of each base class subobject and each member variable.
Such a generated operator may or may not compile, depending of whether all members and base classes are copyable. In such cases it is usual to define the operator manually, to do the assignment correctly, if the class should be copyable at all.
However, the probable reason to call the base class assignment explicitly is that indeed only the base class parts need to be copied, while the other class members should not be changed, so this is not a "real assignment" in the semantical sense.

how to declare default constructor

I have a Base class that I can't modify the source code. I make a derived class from it and I am trying to make a no-argument constructor for this derived class. The problem is that I can't define the constructor for two reasons:
There is not a non-argument constructor defined for the base class to use it.
I can't pass a default value for the constructor of the base.
class base
{
public:
base (A arg)
{
}
};
class derived : public base
{
public:
derived () : base (arg) //ERROR
{
}
};
Is there a solution to define a non-argument constructor for the derived class?
Cordialement,
Since you cannot change the base class the only option left is to pass an argument to its constructor. You can do this quite easily by constructing a temporary instance of A and passing it to the base class in your ctor initialized list of derived classes.
derived::derived () : base (A())
{
}
In the code above base(A()) will create a temporary instance of A and pass it to the constructor of base.

unique_ptr member, private copy constructor versus move constructor

Given a base class for multiple derived class, the goal was to create a wrapper class that allowed an STL container to see objects with the base interface, event though different derived classes may actually be added to the container. (See Retrieve data from heterogeneous std::list).
After some tinkering, I came up with a new derived class that was a wrapper around a unique_ptr to the base class. However, the move constructor has me confused.
class Base {
friend class BaseWrapper;
virtual Base * clone () const = 0;
public:
virtual ~Base () {}
//... public interface
};
class Derived : public Base {
//... specific members for derived class
Base * clone () const { return new Derived(*this); }
public:
//... implement public interface
};
class BaseWrapper : public Base {
std::unique_ptr<Base> ptr_;
Base * clone () const { return ptr_->clone(); }
public:
BaseWrapper (const Base &b) : ptr_(b.clone()) {}
//... implement public interface by forwarding to ptr_
};
typedef std::list<BaseWrapper> BaseList;
int main () {
BaseList l;
l.push_back(Derived());
}
This does not compile with g++ 4.7.2.
Now, in order to use BaseWrapper, I can implement a public move constructor like this:
BaseWrapper (BaseWrapper &&bw) { ptr_.swap(bw.ptr_); }
And this works fine. But, if I make it private, it will not compile.
However, I found that instead of the above, I can instead define a private "copy" constructor (making it public also works, of course):
BaseWrapper (BaseWrapper &bw) { ptr_.swap(bw.ptr_); }
Could someone tell me if this was supposed to work, and why or why not? If it is supposed to work, why can I not make the move constructor private?
You can follow this link to the toy program illustrating the above in a more complete way.
[removed the erroneous diagnostic]
That actually compiles on gcc 4.8. It seems like gcc 4.7 takes BaseWrapper (const Base &) as a copy constructor(which is actually not), and implicitly deletes the move constructor(which would be expected behaviour if it were indeed a copy constructor).

protected inheritance error

#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
public:
derived(){}
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}
Why is this program giving error as In constructor derived::derived():
error: no matching function for call to base::base()
Please explain. As i have read in stackoverflow that in case of inheriting as protected, protected members of base class became protected member of derived class. If I am wrong then please share a good link to clear my misconception
Once you define a constructor for any class, the compiler does not generate the default constructor for that class.
You define the parameterized constructor(base(int i)) for base and hence the compiler does not generate the no argument constructor for base.
Resolution:
You will need to define a constructor taking no arguments for base yourself.
Add this to your base class:
base():a(0)
{
}
EDIT:
Is it needed to define default constructor to every class? Or is it necessary to have the constructor that matches the derived type also present in base type?
The answer to both is NO.
The purpose of constructors in C++ is to initialize the member variables of the class inside the constructor. As you understand the compiler generates the default constructor(constructor which takes no arguments) for every class.
But there is a catch, If you yourself define (any)constructor(one with parameters or without) for your class, the compiler does not generate the default constructor for that anymore. The compiler reasoning here is "Huh, this user writes a constrcutor for his class himself, so probably he needs to do something special in the constructor which I cannot do or understand", armed with this reasoning the compiler just does not generate the default no argument constructor anymore.
Your code above and you assume the presence of the default no argument constructor(When derived class object is created). But since you already defined one constructor for your base class the compiler has applied its reasoning and now it refuses to generate any default argument constructor for your base class. Thus the absence of the no argument constructor in the base class results in the compiler error.
You must give a value to the base constructor:
class Derived : protected base
{
public:
Derived() : base(0)
{
}
};
Depending on your implementation, give the value to the base constructor. However, you may want the Derived constructor to take also int as an argument, and then pass it to the base one.
You need to implement an empty constructor in base or invoke the defined base(int) constructor explicitly from derived c-tor. Without it, when derived c'tor is activated,
it is trying to invoke base() [empty c'tor], and it does not exist, and you get your error.
You haven't defined a default constructor for Base..
When you instantiate an instance of Derived, it will call the Derived() constructor, which will in turn try to call the Base() default constructur which doesn't exist as you haven't defined it.
You can either declare an empty constructor for base Base::Base() or call the existing one as below:
#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
derived(): Base(123) {} --this will call the Base(int i) constructor)
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}