Explicit operator= call (T::operator=) - c++

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.

Related

typeid() returning wrong type [duplicate]

I am attempting to do something like:
class Base {
public:
Base() {
cout << typeid(*this).name() << endl;
}
...
};
class Derived : public Base { ... }
class MoreDerived : public Derived { ... }
Derived d;
MoreDerived m;
Problem is, I always get Base printed to the screen, when I need to see Derived and MoreDerived. Is there a way to get typeid to work this way with derived classes? Or is there another approach besides typeid?
Note: I am adding functionality to an already coded suite, so I don't want to have to add a virtual method to the base class where the derived classes return this value themselves. Also, not worried about runtime overhead, this will be part of a debug compile switch.
In the constructor Base(), the object is still a "Base" instance. It will become a Derived instance after the Base() constructor. Try to do it after the construction and it will work.
See for example :
Avoiding virtual methods in constructor
Never Call Virtual Functions during Construction or Destruction
You can't do that from within a constructor (or destructor) - neither with typeid nor with a virtual method. The reason is while you're in a constructor the vtable pointer is set to the base class being constructed, so the object is of base class and no amount of polymorphism will help at that point.
You have to execute that code after the most derived class has been constructed. One option would be to use a factory function:
template<class T>
T* CreateInstance()
{
T* object = new T();
cout << typeid(*object).name() << endl;
return object;
}
Another option is to provide a virtual toName() function
struct Object{
virtual std::string toName() const = 0;
}
struct Base: Object{
std::string toName()const{ return "Base"; }
}
struct Derived: Base, Object{
std::string toName()const{ return "Derived"; }
This might get tedious since you need to manually create each toName function. But the advantage it gives you is to provide your own custom name.

constructors inherited in c++

Excerpt from here:
Constructors are different from other class methods in that they create new objects, whereas other methods are invoked by existing objects. This is one reason constructors aren’t inherited. Inheritance means a derived object can use a base-class method, but, in the case of constructors, the object doesn’t exist until after the constructor has done its work.
Does a constructor create new object or when a object is called the
constructor is called immediately?
It is said that a constructor and destructor is not inherited
from the base class to the derived class but is the program below a
contradiction, we are creating an object of the derived class but it
outputs constructor and destructor of the base class also?
class A{
public:
A(){
cout<< Const A called<<endl;
}
~A(){
cout<< Dest A called <<endl;
}
};
Class B : public A{
public:
B(){
cout<< Const B called <<endl;
}
~B(){
cout<< Dest B called <<endl;
}
};
int main(){
B obj;
return 0;
}
Output:
Const A called
Const B called
Dest B called
Dest A called
A derived class D does not inherit a constructor from B in the sense that, specifying no explicit D constructors I can use my B(int) like to construct a new D(1);.
However, what I can do is use a base class constructor in the definition of a derived class constructor, like D::D(void) : B(1) {}.
Less abstract, suppose I have a constructor for Person that takes a gender parameter, I might wish to create a:
class Son: Person{
public:
Son(void) : Person(male) {};
};
to construct a Son, which is obviously a Person, but certainly doesn't need parameterised gender.
Destructors are 'inherited' in the sense that on the closing brace of D::~D(){} a call to ~B() is implied.

Inherited operator= not working?

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).

Can I call abstract base class's public assignment operator from another class except subclass?

I run into MISRA C++ 2008 Guidelines, and a rule 12-8-2 in this guideline says:
The copy assignment operator shall be declared protected or private in an abstract class.
and then I thought, when I make an abstract class's assignment operator public,
Is it possible to call it from another class except its subclass?
I think it's impossible.
If this is true, why they define this rule?
Basically, from the point of view of class design, I don't use abstract class which has private member, and I don't define assignment operator in a base class. So, usually, there is no need to apply this rule. However, If there is an abstract base class's public assignment operator, I would make it protected (or private if possible), because it makes no sense to be public. Do you know any other good reasons to apply this rule?
Did I overlook anything?
If they consider a class with virtual function (not pure) an abstract, then most likely to prevent slicing. Normal terminology for it is base class.
#include <iostream>
struct A
{
virtual ~A(){}
virtual void foo(){ std::cout<<1<<std::endl; };
};
struct B : A
{
virtual void foo(){ std::cout<<2<<std::endl; };
};
int main()
{
B b;
A a = b; // ops, wrong output because of slicing
}
However, if your class is really abstract (meaning it has pure virtual methods), then the rule makes no sense.
struct A
{
virtual ~A(){}
virtual void foo() = 0;
};
struct B : A
{
virtual void foo(){}
};
int main()
{
B b;
A a = b; // compilation error
}
I don't define assignment operator in a base class.
It doesn't matter whether you define the assignment operator or not. If you do not do it, the compiler will generate one for you.
Abstract class are the classes whose implementation is unknown but you know how they will behave or interact with other classes. Hence it is unlikely that you know size or other details about abstract class which is actually needed in copy and assignment operators.
Also main problem comes with something earlier answers to this post talks about "Slicing problem" which becomes more problematic in polymorphic classes as assignment operator is not by default virtual.
Consider this
class A
{
};
class B : public A
{
}
int main()
{
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
}
Now in above case a_ref is initialised to b2 object but in next line when it is assigned to b1 it will be A's operator= is called rather than B's operator= which might change other object b2. You can imagine situation where in class A and B are not empty.
Hence it is rule that you either make copy constructor and assignment operator as private not public and in case you make assignment operator public in Abstract class then make it virtual and in every derived implementation check compatibility using dynamic_cast.
By definition, abstract classes cannot be instantiated (e.g. see here). A class that cannot be instantiated cannot be copied. Therefore the rule is absurd.
I confirmed slicing problem pointed out by #BЈовић and #NIRAJ RATHI,
then I noticed a case that It's possible to call public assignment operator in abstract base class by using reference. It's possible but possibly causing slicing problem. So making assignment operator virtual, overriding it in subclass and downcasting is needed.
#include <stdio.h>
class X {
public:
int x;
X(int inx): x(inx) {}
virtual void doSomething() = 0;
virtual void print() { printf("X(%d)\n",x); }
virtual X& operator=(const X& rhs) {
printf("X& X::operator=() \n");
x = rhs.x;
return *this;
}
};
class Y : public X {
public:
int y;
Y(int inx,int iny) : X(inx), y(iny) {}
void doSomething() { printf("Hi, I'm Y."); }
virtual void print() { printf("Y(%d,%d)\n",x,y); }
virtual X& operator=(const X& rhs);
};
X& Y::operator=(const X& rhs) {
printf("X& Y::operator=() \n");
const Y& obj = dynamic_cast<const Y&>(rhs);
X::operator=(rhs);
y = obj.y;
return *this;
}
int main()
{
Y a(1,2);
Y a2(3,4);
X& r = a;
r = a2; // calling assignment operator on ABC without slicing!!
r.print();
}
In my conclusion:
- It's possible to call assignment operator in abstract base class by using reference.
- The rule 12-8-2 is intended to prevent slicing problem.
- If there is no slicing problem, I don't always have to apply the rule 12-8-2.
BЈовић: However, if your class is really abstract (meaning it has pure virtual methods), then the rule makes no sense.
It does, as the assignment operator could accidentaly be called on pointers/references to the base class, which would always lead to slicing.
class cA
{
public:
int x;
virtual ~cA() { }
virtual void f() = 0;
};
class cB: public cA
{
int y;
virtual void f() { }
};
cA * a = new cB, * b = new cB;
*a = *b; // slicing: x is copied, y is not
The rule does make sense for a couple of reasons:
prevent partial assignment
prevent copying between incompatible classes
Suppose we have an abstract base class Animal and a couple of derived classes, Lizard and Chicken:
class Animal {
public:
...
};
class Lizard: public Animal {
...
};
class Chicken: public Animal {
...
};
The assignment operator by default is public. Now consider this code:
Lizard liz1;
Lizard liz2;
Animal *pAnimal1 = &liz1;
Animal *pAnimal2 = &liz2;
...
*pAnimal1 = *pAnimal2;
The assignment operator invoked on the last line is that of the Animal class, even though the objects involved are of type Lizard. Therefore, only the Animal part of liz1 will be modified. This is a partial assignment. After the assignment, liz1's Animal members have the values they got from liz2, but liz1's Lizard members remain unchanged.
It also possible via Animal pointers to assign a Lizard to a Chicken. That doesn't make a lot of sense, since they are incompatible with each other, and we might want to prevent such a thing happening. The easiest way to prevent such assignments is to make operator= protected in Animal. That way, lizards can be assigned to lizards and chickens can be assigned to chickens, but partial and mixed-type assignments are forbidden:
class Animal {
protected:
Animal& operator=(const Animal& rhs);
...
};
Alternatively, the assignment operator can be defined =delete if copying is to be prohibited in this class hierarchy. Actually, assignment operators that are private or protected needn't return *this at all. They can return the type void.

how to force base class constructors to be called in derived classes?

basic c++ question i'm fairly sure. if i have a base class with a constructor that takes no parameters, and just initializes some of the protected members, does a derived class instantly call this base constructor too if it matches the parameters (wishful but unlikely thinking), and if not, is there a way to force it to automatically call said base constructor from the derived class WITHOUT having to explicitly tell it to do so in the derived class? I ask because i'm writing a wrapper of sorts and there are some protected members that i want initialized to specific values initially, and then i want to derive and manipulate this base class to my needs, but i wouldn't like an outside user to have to remember to explicitly call the base constructor or set these values within their own constructor.
Yes, the default base constructor is always called unless explicitly stated otherwise.
For example:
class A
{
public:
A() { std::cout << "A"; }
};
class B : A
{
public:
B() {}
};
int main()
{
B b;
return 0;
}
will output:
A
By "explicitly stated otherwise" I mean that you can call a different constructor from the derived class:
class A
{
public:
A() { std::cout << "A"; }
A(int) { std::cout << "AAA"; }
};
class B : A
{
public:
B() : A(1) {} //call A(int)
};
int main()
{
B b;
return 0;
}
will output
AAA
Important if you don't have a default constructor (you declare a non-default constructor and not a default one) or the default constructor is not visible (marked as private), you need to explicitly call an available constructor in the derived class.
If your base-class has a "default constructor" (a constructor that takes no parameters; either explicitly provided by you, or implicitly provided by the compiler because you didn't explicitly provide any constructors), then every derived-class constructor will automatically call that unless you specify that they call a different constructor instead.
(If your base-class doesn't have a "default constructor", because you've provided one or more constructors that take parameters and no constructor that doesn't, then it's a compile-error for a derived-class constructor not to indicate the base-class constructor it calls.)