Size of derived class in virtual base class function - c++

Consider the following code
class A {
int x, y;
public:
A(){}
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class B : public A {
int a, b, c;
public:
B(){}
};
int main() {
A obja;
B objb;
obja.PrintSize();
objb.PrintSize();
}
The intent of "PrintSize()" is to get the size of the current class where we are calling it from. What happens is that this-keyword refers to class A even though we are calling it from B. We don't want this since we need this function to be general for child classes.
We could obviously redefine the function verbatim to every class. The code would become harder to hande since there's so many unnesessary lines. Not to mention that re-writing the function to every class would defeat the purpose of deriving it in the first place.
Here's my temporary fix:
class A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class B : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class C : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};
class D : public A {
public:
virtual void PrintSize(){ cout << sizeof(typeof(*this)) << endl; }
};

While the accepted answer may have solved the immediate problem, you suddenly have no common base class for B and C. They inherit from two unrelated classes, namely A<B> and A<C>.
An alternative is to create a common base that defines an interface (called Interface below) and to add the CRTP class template between the derived classes and the interface. This lets you keep pointers and references to Interface and call the virtual member functions using those.
Here's an example of storing pointers to the common base class in a vector:
#include <iostream>
#include <memory>
#include <vector>
struct Interface {
virtual ~Interface() = default;
virtual void PrintSize() const = 0;
virtual void do_stuff() const = 0;
};
template<typename T>
struct Printer : public Interface {
void PrintSize() const override {
std::cout << sizeof(T) << '\n';
}
};
class B : public Printer<B> {
int a{};
public:
void do_stuff() const override { std::cout << "B doing stuff\n"; }
};
class C : public Printer<C> {
int a{}, b{}, c{};
public:
void do_stuff() const override { std::cout << "C doing stuff\n"; }
};
int main() {
std::vector<std::unique_ptr<Interface>> objs;
objs.emplace_back(std::make_unique<B>());
objs.emplace_back(std::make_unique<C>());
for(auto& ptr : objs) {
ptr->do_stuff();
ptr->PrintSize();
}
}
Possible output:
B doing stuff
16
C doing stuff
24

You can use the CRTP idiom to do this.
https://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c
The idea is the parent class is a template, so you can have access to the type of the child class directly in it.
With that, you'll be able to remove all "PrintSize" from child class.
Example :
template <typename Derived>
class A {
int x, y;
public:
A() {}
void PrintSize() { cout << sizeof(Derived) << endl; }
};
class B : public A<B> {
int a, b, c;
public:
B() {}
};
class C : public A<C> {
public:
C() {}
};
int main() {
C objc;
B objb;
objc.PrintSize();
objb.PrintSize();
}
The output is :
8
20

Related

C++ Polymorphism : Is it possible to use a function from a double derived class into the base class?

I'm new to polymorphism and I'm trying to learn how this exactly works .
I want for example to get the print() function of class Y and use it in the base class .
Is this possible to do ?
class A
{
public:
A() = default;
virtual void print()
{
//Is it possible to get the print() function of class Y here ?
};
};
class B : public A
{
public:
B() = default;
void print(){ std::cout << "B " << std::endl;}
};
class C : public A
{
public:
C() = default;
void print(){ std::cout << "C " << std::endl;}
};
class Y : public C , public B
{
public:
Y() = default;
void print()
{
B::print();
C::print();
}
};
int main()
{
A a;
a.print();
return 0;
}
Your main() is creating an A object directly, not a Y object. That is why you are not seeing the output you want. Polymorphism only works when accessing derived class objects via base class pointers/references, eg:
int main()
{
Y y;
A *a = static_cast<C*>(&y);
a->print();
return 0;
}
int main()
{
Y y;
A &a = static_cast<C&>(y);
a.print();
return 0;
}
The reason for the type cast is becauseY has 2 A portions, one from B and one from C, so you have to help the compiler a little by specifying which A you want to point to.

Overriding virtual methods separately in multiple inheritance layout

Is there a way to override separately functions with same names (from two parents) in a base class?
I am looking for something like this:
#include<iostream>
using namespace std;
class A {
public:
virtual void foo() {
cout << "A::Foo" << endl;
}
};
class B {
public:
virtual void foo() {
cout << "B::Foo" << endl;
}
};
class C : public A, public B {
public:
/*virtual void A::foo() {
cout << "C::Foo" << endl;
}*/
};
int main() {
C c;
c.A::foo(); // want to get C::Foo here
}
No you can't do this. If you want to avoid access to class A; via class C; explicit scope resolution make A private:
class C : private A, public B {
// ^^^^^^^
public:
};
If you want to prefer the implementation of A you can specify what you want to use explicitly:
class C : public A, public B {
public:
using A::foo();
};

Call virtual function after derived class object construction

Here is some sample code:
#include <iostream>
class A {
public:
virtual void foo() {
std::cout << "base" << std::endl;
}
A() {
foo();
}
};
class B : public A {
int a;
public:
void foo() {
std::cout << "derived" << std::endl;
}
B(int a) :
a(a) {}
};
int main() {
B o(1);
return 0;
}
I want foo() to get called every time some A derived object is constructed. I do not want to call foo() explicitly in every derived class constructor.
Is there a way to do this in some elegant way?
There is no way you can call an overridden foo() from a base class constructor, no matter what you do. When the base class constructor is called, the derived class object has not been constructed yet, so you cannot call any of its methods or access any of its members. This is true for virtual functions and regular functions as well. In a base class constructor, the this pointer is pointing at the base class, not the derived class.
A potential workaround is to delegate construction to a separate function that clients will have to call instead. Then have that function call foo after construction:
class A {
public:
virtual void foo() {
std::cout << "base" << std::endl;
}
template<typename T, typename ... Args>
static T construct(Args ... args)
{
T newT{ args... };
newT.foo();
return std::move(newT);
}
protected:
A() {
//Construct A
}
};
class B : public A {
int a;
public:
void foo() {
std::cout << "derived" << std::endl;
}
B(int a) :
a(a) {}
};
int main()
{
B o = A::construct<B>(1);
A a = A::construct<A>();
return 0;
}

c++ multi inheritence order and virtual functions

Does it important in which order you inheritence abstact classes, which has same functions ?
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
class C : public A {
public:
virtual void f1() { globalF1_C(); }
};
class D : public A, public B, public C { };
class E : public A, public C, public B { };
Does D and E classes would be the same, if I would write it like below:
class D{
public:
virtual void f1() { globalF1_C(); }
virtual void f2() { globalF2_B(); }
};
class E {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
PS. I inheritence class A into class D and class E just in case I can forget make some realization of class A's function.
No there are not the same. Besides an invalid C++ code provided, we can say :
In the first case your classes D and E have two method f1() (one inherited from B and one inherited from C) and one method f2() (inherited from C). If you would be able to construct a D object name d, then d.f1() would be reported as an ambiguity that you would need to clarify either this way : d.B::f1() or this one d.C::f1().
While in the second case your classes will only have two methods f1() and f2().
#include <iostream>
using namespace std;
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { cout << "B::f1()" << endl; }
virtual void f2() { cout << "B::f2()" << endl; }
};
class C : public A {
public:
virtual void f1() { cout << "C::f1()" << endl; }
virtual void f2() { cout << "C::f2()" << endl; }
};
class D : public B, public C { };
class E : public C, public B { };
int main() {
D d;
// d.f1(); // t.cpp:28:5: error: member 'f1' found in multiple base classes of different types
d.C::f1();
d.B::f1();
}
NO, the first version of D & E won't compile either. there would be ambiguity in resolving f1 and f2 in D and E

C++11 Declaring factory a friend of base class

I'm trying to create a factory for derived classes. I only want the factory to be able to create instances of the derived classes so I've made the base constructor protected; the derived classes just use the base class constructors so their constructors are protected also.
I tried to declare the factory as a friend of the base class so that it could access the protected constructor. When I compile using this command
clang++ -std=c++11 -stdlib=libc++ Friends.cpp -o Friends
I get this error:
Friends.cpp:23:20: error: calling a protected constructor of class 'A'
return new T(i);
^
Friends.cpp:42:16: note: in instantiation of function template specialization 'Create<A>' requested
here
A* a = Create<A>(1);
^
Friends.cpp:30:25: note: declared protected here
using Base::Base;
^
Along with a similar error for derived class B.
I get the feeling from reading other questions on stackoverflow.com, that this isn't possible in C++11, but I'm not sure why. Can someone explain why this won't work and perhaps an alternative?
Example code
#include <iostream>
using namespace std;
// Forward declaration
template<class T> T* Create(int i);
class Base {
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
protected:
Base(int i): i(i) { } // This won't compile
int i;
};
// Factory for Base class
template<class T>
T* Create(int i){
return new T(i);
}
class A: public Base {
public:
using Base::Base;
void say() { cout << "I am A and have a value of " << i << endl; }
};
class B: public Base{
public:
using Base::Base;
void say() { cout << "I am B and have a value of " << i << endl; }
};
int main(){
cout << "I'm creating A." << endl;
A* a = Create<A>(1);
a->say();
cout << "I'm creating B." << endl;
B* b = Create<B>(2);
b->say();
return 0;
}
When you inherit a constructor from a base class it retains the access of the original constructor, regardless of where you place the using declaration in the derived class.
From ยง12.9/4 [class.inhctor]
A constructor so declared has the same access as the corresponding constructor in X. ...
You can fix the error if you explicitly add constructors to derived classes instead of inheriting them from Base.
A(int i) : Base(i) {}
and
B(int i) : Base(i) {}
Live demo
Another solution, of course, is to make Base's constructor public. You could also make its destructor protected, but it's not necessary since the class cannot be instantiated anyway due to the pure virtual member function.
class Base {
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
Base(int i): i(i) { } // This won't compile
int i;
protected:
~Base() {}
};
Live demo
Friendship does not go down the inheritance tree. Create is friend of Base, and therefore can not access the protected A::A(int) and B::B(int).
Possible solutions include:
Make new friendships (A, B and further child classes should be friends of Create)
Use public constructors as mentioned by #Snps
Use an external class that only Base (and therefore also its friend, Create) can create and the rest can only copy. Idea from here.
Code for last solution:
#include <iostream>
using namespace std;
// Forward declaration
template<class T> T* Create(int i);
class Base {
class AccessKey {
friend class Base;
AccessKey() {};
public:
AccessKey(const AccessKey& o) {}
};
static AccessKey getAccessKey() { return AccessKey(); }
public:
template<class T>
friend T* Create(int);
virtual void say() = 0;
Base(int i, AccessKey k): i(i) { } // This can be public as it can be called without and AccessKey object
protected:
int i;
};
// Factory for Base class
template<class T>
T* Create(int i){
return new T(i, Base::getAccessKey());
}
class A: public Base {
public:
using Base::Base;
void say() { cout << "I am A and have a value of " << i << endl; }
};
class B: public Base{
public:
using Base::Base;
void say() { cout << "I am B and have a value of " << i << endl; }
};
int main(){
cout << "I'm creating A." << endl;
A* a = Create<A>(1);
a->say();
cout << "I'm creating B." << endl;
B* b = Create<B>(2);
b->say();
return 0;
}
I would be tempted to make the Create() function a static member of Base and then just make all the derived classes friends of Base:
Run This
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
// Factory for Base class
template<class T>
static T* Create(int i) {
static_assert(std::is_base_of<Base, T>::value, "Needs to be derived from Base");
return new T(i);
}
virtual void say() = 0;
protected:
Base(int i): i(i) { }
int i;
};
class A: public Base {
friend Base; // Allow Base to construct
public:
using Base::Base;
void say() { cout << "I am A and have a value of " << i << endl; }
};
class B: public Base {
friend Base; // Allow Base to construct
public:
using Base::Base;
void say() { cout << "I am B and have a value of " << i << endl; }
};
int main(){
cout << "I'm creating A." << endl;
A* a = Base::Create<A>(1);
a->say();
cout << "I'm creating B." << endl;
B* b = Base::Create<B>(2);
b->say();
return 0;
}
EDIT: Added static_assert
EDIT: Added link to run code