Preventing redundant function calls in the presence of diamond inheritance - c++

What's a good strategy for preventing redundant function calls in the presence of diamond inheritance? Specifically, say we have a program:
#include <iostream>
struct A {
int a;
A(int a_) : a(a_) {}
virtual void print() {
std::cout << "a: " << a << std::endl;
}
};
struct B : virtual public A {
int b;
B(int a_,int b_) : A(a_), b(b_) {}
virtual void print() {
A::print();
std::cout << "b: " << b << std::endl;
}
};
struct C : virtual public A {
int c;
C(int a_,int c_) : A(a_), c(c_) {}
virtual void print() {
A::print();
std::cout << "c: " << c << std::endl;
}
};
struct D : public B,public C {
int d;
D(int a_,int b_,int c_,int d_) : A(a_), B(a_,b_), C(a_,c_), d(d_) {}
void print() {
B::print();
C::print();
std::cout << "d: " << d << std::endl;
}
};
int main() {
D d(1,2,3,4);
d.print();
}
When we call d.print(), we get:
a: 1
b: 2
a: 1
c: 3
d: 4
where a has been printed twice. Is there a good way to prevent this? Certainly, we could manually wire the connections with a code like:
#include <iostream>
struct A {
int a;
A(int a_) : a(a_) {}
virtual void print_() {
std::cout << "a: " << a << std::endl;
}
virtual void print() {
A::print_();
}
};
struct B : virtual public A {
int b;
B(int a_,int b_) : A(a_), b(b_) {}
virtual void print_() {
std::cout << "b: " << b << std::endl;
}
virtual void print() {
A::print_();
B::print_();
}
};
struct C : virtual public A {
int c;
C(int a_,int c_) : A(a_), c(c_) {}
virtual void print_() {
std::cout << "c: " << c << std::endl;
}
virtual void print() {
A::print_();
C::print_();
}
};
struct D : public B,public C {
int d;
D(int a_,int b_,int c_,int d_) : A(a_), B(a_,b_), C(a_,c_), d(d_) {}
virtual void print_() {
std::cout << "d: " << d << std::endl;
}
virtual void print() {
A::print_();
B::print_();
C::print_();
D::print_();
}
};
int main() {
D d(1,2,3,4);
d.print();
}
which correctly outputs
a: 1
b: 2
c: 3
d: 4
but I would like to know if there's a better way. In terms of where this arises, imagine a situation with the objects A, B, C, and D are complicated and need to be able to write themselves to disk. We only want to write the output code for each A, B, C, and D once and it's important that D not write information about A twice.
<---EDIT--->
Here's two more ways of fixing the problem, but they're still kind of obtuse. The first one is from Cristian and involves setting a flag on whether or not A has been printed
#include <iostream>
struct A {
int a;
bool have_printed;
A(int a_) : have_printed(false), a(a_) {}
virtual void print() {
if(have_printed) return;
std::cout << "a: " << a << std::endl;
have_printed=true;
}
void clear() {
have_printed=false;
}
};
struct B : virtual public A {
int b;
B(int a_,int b_) : A(a_), b(b_) {}
virtual void print() {
A::print();
std::cout << "b: " << b << std::endl;
}
};
struct C : virtual public A {
int c;
C(int a_,int c_) : A(a_), c(c_) {}
virtual void print() {
A::print();
std::cout << "c: " << c << std::endl;
}
};
struct D : public B,public C {
int d;
D(int a_,int b_,int c_,int d_) : A(a_), B(a_,b_), C(a_,c_), d(d_) {}
void print() {
B::print();
C::print();
std::cout << "d: " << d << std::endl;
}
};
int main() {
D d(1,2,3,4);
d.clear();
d.print();
}
This correctly outputs. A second way is more complicated, but may allow the structure to grow. Basically, we separate out the printer from the class and then register a list of printers inside each object. When we want to print, we iterate over the list of printers, which then gives us the correct output. I feel this uses too much machinery, but I'll include in case someone else gets a better idea:
// A simple unary function. Technically, the stl version doesn't require
// the operator
template <typename A,typename B>
struct unary {
virtual B operator () (A a) {};
};
struct A {
// Data
int a;
// A list of pointers to unary functions. We need pointers to unary
// functions rather than unary functions since we need the printer
// to be polymorphic.
std::list < unary<A*,void>* > printers;
A(int a_);
// We actually end up allocating memory for the printers, which is held
// internally. Here, we free that memory.
~A() {
for(std::list < unary<A*,void>* >::iterator printer
=printers.begin();
printer != printers.end();
printer++
)
delete (*printer);
}
private:
// Require for the dynamic cast used later
virtual void ___dummy() {};
};
// Prints out the data for A
struct A_Printer : public unary<A*,void>{
void operator () (A* a) {
std::cout << "a: " << a->a << std::endl;
}
};
// Adds the printer for a to the list of printers
A::A(int a_) : a(a_) {
printers.push_back(new A_Printer());
}
// Now that the structure is setup, we just need to define the data for b,
// it's printer, and then register the printer with the rest
struct B : virtual public A {
int b;
B(int a_,int b_);
};
struct B_Printer : public unary<A*,void>{
void operator () (A* b) {
std::cout << "b: " << dynamic_cast <B*>(b)->b << std::endl;
}
};
B::B(int a_,int b_) : A(a_), b(b_) {
printers.push_back(new B_Printer());
}
// See the discussion for B
struct C : virtual public A {
int c;
C(int a_,int c_);
};
struct C_Printer : public unary<A*,void>{
void operator () (A* c) {
std::cout << "c: " << dynamic_cast <C*>(c)->c << std::endl;
}
};
C::C(int a_,int c_) : A(a_), c(c_) {
printers.push_back(new C_Printer());
}
// See the discussion for B
struct D : public B,public C {
int d;
D(int a_,int b_,int c_,int d_);
};
struct D_Printer : public unary<A*,void>{
void operator () (A* d) {
std::cout << "d: " << dynamic_cast <D*>(d)->d << std::endl;
}
};
D::D(int a_,int b_,int c_,int d_) : A(a_), B(a_,b_), C(a_,c_), d(d_) {
printers.push_back(new D_Printer());
}
// This actually prints everything. Basically, we iterate over the printers
// and call each one in term on the input.
void print(A* a) {
for(std::list < unary<A*,void>* >::iterator printer
=a->printers.begin();
printer != a->printers.end();
printer++
)
(*(*printer))(a);
}
int main() {
D d(1,2,3,4);
// This should print 1,2,3,4
print(&d);
}
<---EDIT 2--->
tmpearce had a good idea to accumulate all of the information in a hash table prior to assembling it. In this way, it's possible to check if the individual information has been created yet and prevent redundancies. I think this is a good idea when the information can be assembled easily. If this is not the case, a slight variation may work, which combines the ideas of tmpearce and Cristian. Here, we pass around a set (or hashtable, or whatever) that keeps track of whether or not a function has been called. In this way, we can check whether or not some function has been computed. It doesn't require perpetual state, so it should be safe to call multiple times:
#include <iostream>
#include <set>
struct A {
int a;
A(int a_) : a(a_) {}
virtual void print_(std::set <std::string>& computed) {
if(computed.count("A") > 0) return;
computed.insert("A");
std::cout << "a: " << a << std::endl;
}
void print() {
std::set <std::string> computed;
print_(computed);
}
};
struct B : virtual public A {
int b;
B(int a_,int b_) : A(a_), b(b_) {}
virtual void print_(std::set <std::string>& computed) {
A::print_(computed);
if(computed.count("B") > 0) return;
computed.insert("B");
std::cout << "b: " << b << std::endl;
}
};
struct C : virtual public A {
int c;
C(int a_,int c_) : A(a_), c(c_) {}
virtual void print_(std::set <std::string>& computed) {
A::print_(computed);
if(computed.count("C") > 0) return;
computed.insert("C");
std::cout << "c: " << c << std::endl;
}
};
struct D : public B,public C {
int d;
D(int a_,int b_,int c_,int d_) : A(a_), B(a_,b_), C(a_,c_), d(d_) {}
virtual void print_(std::set <std::string>& computed) {
B::print_(computed);
C::print_(computed);
if(computed.count("D") > 0) return;
computed.insert("D");
std::cout << "d: " << d << std::endl;
}
};
int main() {
D d(1,2,3,4);
d.print();
}
In any case, I'll mark this problem off as solved. Though, I'd always like to hear additional answers.

My approach would sort of combine the ones you've mentioned. I'd make the virtual method do something a bit different:
class A
{
public:
virtual void getInfo(std::map<std::string,std::string>& output)
{
if(output.count("A") == 0)
{
output["A"] = "a: 1";
}
}
void print()
{
std::map<std::string,std::string> m;
getInfo(m); //virtual method (most derived will be called)
std::map<std::string,std::string>::iterator iter = m.begin();
for(; iter!=m.end(); ++iter)
{
std::cout<<iter->second();
}
}
};
class B : public A
{
virtual void getInfo(std::map<std::string,std::string>& output)
{
A::getInfo(output);
if(output.count("B") == 0)
{
output["B"] = "b: 2";
}
}
};
print is now a non-virtual method that uses getInfo to populate a container, then iterates over it display/save the output. Each class can thus check to make sure the container doesn't already contain the desired output for that level of the inheritance chain before writing and adding the string to the container.

I'd add a private flag to A struct (and to B and C if diamond extends beyond one level) and checking it & marking it as already traversed. This would also help in more complicated (nested) diamond patterns.
Like this:
struct A {
int a;
A(int a_) : a(a_) {traversed = false;}
virtual void print() {
if (traversed) return;
std::cout << "a: " << a << std::endl;
traversed = true;
}
private:
bool traversed;
};

Only one class constructs the virtual base (the most derived, D) so I would ensure only one class prints the A object, and like its construction, make it happen first (possibly important if you're writing objects to disk.)
You could add a void* argument to A's constructor and store it in a member of A. Each derived class would construct the virtual base as A(a, this).
Add a new member function to A, do_print(void*) and have every derived class call do_print(this) instead of A::print(). The do_print(void*) function compares its argument with the stored void* passed to the A ctor and only prints if it's the same. This relies on every derived class having a distinct address, which will be true if all the classes are non-empty, but if that assumption holds it ensures only the most derived object prints the virtual base.

Related

Base class pointer as private member

I am working on a system where a class has a private member that is a base class pointer. The pointer can be pointing to an inherited class object. I would like the parameterized and copy constructors to be able to take a pointer of the base class type and deep copy it without erasing the inherited type. Here is some code I made to demonstrate this problem; I would like c2 and c3 to call B.print instead of A.print, but can't figure out how.
#include <iostream>
class A
{
protected:
double a;
double b;
public:
A()
{
a = 0.0;
b = 0.0;
}
A(double a, double b)
{
this->a = a;
this->b = b;
}
A(const A& copy)
{
a = copy.a;
b = copy.b;
}
virtual void print()
{
std::cout << "print A" << std::endl;
std::cout << "a: " << a << ", b: " << b << std::endl;
}
};
class B : public A
{
private:
double c;
public:
B()
{
c = 0.0;
}
B(double a, double b, double c) : A(a, b)
{
this->c = c;
}
B(const B& copy) : A(copy)
{
c = copy.c;
}
virtual void print()
{
std::cout << "print B" << std::endl;
std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
}
};
class C
{
private:
A* a;
public:
C()
{
a = nullptr;
}
C(A* a)
{
this->a = new A(*a);
}
C(const C& copy)
{
a = nullptr;
if (copy.a != nullptr)
a = new A(*copy.a);
}
~C()
{
delete a;
a = nullptr;
}
void print()
{
if (a != nullptr)
a->print();
}
};
int main()
{
A* a = new A(3.5, 4.5);
A* b = new B(3.5, 4.5, 5.5);
C c1(a), c2(b), c3(c2);
delete a, b;
c1.print();
c2.print();
c3.print();
}
I have tried including an enum of the available types and storing that value separately, but that program was non-extensible as it would require changing a switch and enum for each added inherited type.
Your actual problem is with these lines:
C(A* a) {
this->a = new A(*a);
}
C(const C& copy) {
a = nullptr;
if (copy.a != nullptr)
a = new A(*copy.a);
}
which explicitly create an object with dynamic type A, ignoring the dynamic types of a and copy.a.
The usual pattern for copying something's real dynamic type is
struct Base
{
// copy ctor etc. as usual
virtual Base* clone() const { return new Base(*this); }
};
struct Derived: Base
{
virtual Base* clone() const { return new Derived(*this); }
};
Other, miscellaneous notes:
You don't need to burn 6 lines on a default constructor that does nothing any more. Just write
class A
{
protected:
double a{};
double b{};
and let the compiler default it. You can default most of your copy constructors too.
If you're controlling pointer lifetime (as C is), just use std::unique_ptr. It's there, it's free, it's much more explicit about your semantics.
When you're owning (ie, controlling the lifetime of) a polymorphic object via a base-class pointer, that base class needs to have a virtual destructor (unless you're doing something exotic with a type-erased deleter, which is out of scope here).
If you've decided to use this->a for data members, use it consistently. If you're only using it for disambiguation, just change the parameter/local variable name so it doesn't collide in the first place.
There are member-naming conventions like m_a or just a_ which make it easy to see which variables are data members, remove ambiguity, and are still less typing/visual noise than randomly sprinkling this-> around.
Working code with only the changes described above:
#include <iostream>
#include <memory>
class A
{
protected:
double a_{};
double b_{};
public:
A() = default;
A(double a, double b) : a_(a), b_(b) {}
A(const A&) = default;
virtual ~A() = default;
virtual A* clone() const { return new A(*this); }
virtual void print()
{
std::cout << "print A" << '\n'
<< "a: " << a_ << ", b: " << b_ << '\n';
}
};
class B : public A
{
double c_{};
public:
B() = default;
B(double a, double b, double c) : A(a, b), c_(c) {}
B(const B&) = default;
virtual B* clone() const override { return new B(*this); }
virtual void print() override
{
std::cout << "print B" << '\n'
<< "a: " << a_ << ", b: " << b_ << ", c: " << c_ << '\n';
}
};
// owns and deep-copies an A.
// class invariant: ptr_ is non-null
//
class C
{
private:
std::unique_ptr<A> ptr_;
public:
explicit C(A* a) : ptr_(a->clone()) {}
C(const C& copy) : ptr_(copy.ptr_->clone()) {}
void print()
{
ptr_->print();
}
};
int main()
{
A a{3.5, 4.5};
B b{3.5, 4.5, 5.5};
C c1(&a), c2(&b), c3(c2);
c1.print();
c2.print();
c3.print();
}
NB. The top-level dynamic allocation was unnecessary even if you do want C to deep copy, so I just removed it entirely instead of either changing it to also use unique_ptr or fixing that incorrect delete statement.

How to initialize member variables before inherited classes

I'm trying to make one class which requires member variables to be initialized first. I know why this happens, but is there a way around this?
Current print order:
second
first
Wanted print order:
first
second
#include <iostream>
struct A {
A() {
std::cout << "first" << '\n';
}
};
struct B {
B() {
std::cout << "second" << '\n';
}
};
struct C : public B {
C() : a(), B() {
}
A a;
};
int main() {
C c;
return 0;
}
Stick your members that need initializing first in a struct and inherit privately from that, before B.
struct A {
A() { std::cout << "first" << '\n'; }
};
struct B {
B() { std::cout << "second" << '\n'; }
};
struct Members { A a; };
struct C : private Members, public B {
C() : Members(), B() {}
};
int main() {
C c;
}
The downside with this is that there is no way to avoid exposing the "member struct" to the outside world, but that shouldn't be a problem in practice.
In C++ base classes will be initialized before any member variables of a derived class.
The best recourse given the information you've provided is to prefer composition over inheritance:
struct A {
A() {
std::cout << "first" << '\n';
}
};
struct B {
B() {
std::cout << "second" << '\n';
}
};
struct C {
A a;
B b;
};
This will exhibit the desired behavior
Make A a needed reference for C:
#include <iostream>
struct A {
A() {
std::cout << "first" << '\n';
}
};
struct B {
B() {
std::cout << "second" << '\n';
}
};
struct C : public B {
C(const A& a) : _A(a), B() {}
const A& _A;
};
int main() {
A a;
C c(a);
return 0;
}

Multiple and virtual inheritance C++

Full disclaimer, this is homework - not graded, just given to students so we can practice.
I'm asking for help, because we won't get an answer and I just want to know how to solve it.
What I can do is define structures B and C. Their interface has to be "like A's interface, with modifications so it works correctly".
I can't add any new methods. I also can't change anything in struct A.
This is the code:
#include <iostream>
struct A;
struct B;
struct C;
struct A {
A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
int main(){
C c;
}
And the desired output is:
A::A()
A::A()
B::B()
A::A()
A::A()
B::B()
A::A()
C::C()
What I tried to do so far:
First I started like this, just to check things out:
struct B : public A {
B() : A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
struct C : public B {
C() : B() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
Which gave me:
A::A()
B::B()
C::C()
So I tried to get first C, then A, then B, then A (desired output from the bottom):
struct B : public virtual A {
B() : A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
struct C : public B, public A {
C() : A(), B() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
But of course this didn't work. (warning: direct base ā€˜Aā€™ inaccessible in ā€˜Cā€™ due to ambiguity)
Adding virtual keyword like below gave me again C, B then A, from the bottom:
struct B : public virtual A {
B() : A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
struct C : public virtual A, public B {
C() : A(), B() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
If I want to get C, then A I have to do the following (but then there will be no B)
struct C : public virtual A {
C() : A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
struct B : public virtual A, public C {
B() : C(), A() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
I also have no idea how could I get A::A() twice in a row.
I just want to understand how this should work, but if you still feel like you don't want to help me with a solution, then please leave me some tips.
I do not see a restriction in the exercise on use of class members:
struct A
{
A() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct B : A
{
B() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct C
: B
, A
{
C() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
B b;
A a;
};
UPDATE
The desired output had changed since my first answer was posted. So previous answer had become wrong. But now you see the point - you can use composition and copy A a; to B definition and remove A inheritance from C definition.
You can do something like:
struct B : A { //inherit from A
B() {
A();
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
struct C : B { //inherit from B
C() {
B(); //anonymous B object
A(); //anonymous A object
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
Running sample

Something I can not figure out about Vtable and Vptr in Multiple Inheritance

The following code
class B
{
public:
void f1() {}
};
class C
{
public:
void f2() {}
};
class D : public B, public C
{
public:
virtual void f3() {}
};
int main()
{
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
system("pause");
return 0;
}
gets a result 1 1 8.So why is 8 not 4(in my computer,a pointer takes 4 bytes)?
B,C do not have vptr, and when D has virtual members, D's Vptr is placed in the Vtable of the first inherited class which is B,since the following code
class B
{
public:
virtual void f1() {} //now is virtual
};
class C
{
public:
void f2() {}
};
class D : public B, public C
{
public:
virtual void f3() {}
};
int main()
{
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
system("pause");
return 0;
}
gets a result 4,1,4. May somebody explain it to me, thanks a lot!

How can I omit a class inheritance?

I'm trying to find my way around. I have two classes, A and B, where B inherits from A.
There are also two overloaded functions for A and B, that act on them in two different ways.
Now call these functions from a class function like this:
#include <iostream>
struct A;
struct B;
void f(A a);
void f(B b);
struct A {
int i;
A(): i(0) {};
void thisf() { f(*this); }
};
struct B: public A {
int j;
B(): j(1) {};
void thisf() { f(*this); }
};
void f(A a) { std::cout << a.i << std::endl; }
void f(B b) { std::cout << b.i << " " << b.j << std::endl; }
int main() {
A a;
B b;
a.thisf();
b.thisf();
return 0;
}
My question is: since A::thisf() and B::thisf() are the same (and will stay the same for more subclasses), is there a way how I can omit B::thisf() while still having the same functionality?
The expected output should look like:
0
0 1
More detail why I try to do this: I want to provide some custom render functionality to different kinds of data without bloating the class with render logic and have a separate render class with some state variables. But I don't want to give up the possibility to write
b.render()
in some situations. In my class definitions I want to spare every line I can.
I got the idea in this thread: https://gamedev.stackexchange.com/questions/63912/visitor-pattern-vs-inheritance-for-rendering
In your proposed problem you claim the need for a method in A and B that is not polymorphic and yet exhibits different behaviour in the two classes (linked by inheritance) with the same signature.
In addition, the method defers to a free function found by ADL (good!).
So... my question to you is this. If you already have the guarantee of a free function called f(A|B), why not simply document that as the interface?
If you insist on having thisf() you are causing yourself a problem because the inheritance relationship will cause B's thisf() to be ambiguous with A's. This can be solved with polymorphism (as per the other answer) but since you're rejecting that, you are are left with few options other than to eliminate the logically redundant thisf() altogether.
in any case, this code will do exactly as you want:
#include <iostream>
struct A;
struct B;
void f(A a);
void f(B b);
struct common_interface {
virtual void thisf() = 0;
};
template<class Host, class Base>
struct common_interface_impl : Base {
virtual void thisf() {
f(static_cast<Host&>(*this));
}
};
struct A : common_interface_impl<A, common_interface>
{
int i;
A(): i(0) {};
};
struct B: common_interface_impl <B, A>
{
int j;
B(): j(1) {};
};
void f(A a) { std::cout << a.i << std::endl; }
void f(B b) { std::cout << b.i << " " << b.j << std::endl; }
int main() {
A a;
B b;
a.thisf();
b.thisf();
return 0;
}
#include <iostream>
struct A {
int i;
A(): i(0) {};
virtual ~A() {};
virtual void thisf() { std::cout << i << std::endl; }
};
struct B: public A {
int j;
B(): j(1) {};
void thisf() { A::thisf(); std::cout << j << std::endl; }
};
void f( A* a )
{
a->thisf();
}
int main() {
A* a = new A();
A* b = new B();
f( a ); f( b );
delete a; delete b;
return 0;
}