-3

I have a base class in a library which I don't want to modify for compatibility reasons. This class stores certain settings that cannot be modified after construction; the correct arguments must be provided at the time of construction.

My own code contains a class that is derived from that class. The argument structure of the constructor of the the derived class is different from the constructor of the base class; arguments are not simply passed through to the base class constructor.

There are three predetermined sets of arguments that will be used to construct the base class from the derived class. The decision as to which of these three to use is based upon the arguments to the derived class constructor. Since the base class arguments are needed in the member initializer list, this decision needs to be made before entering the derived constructor's body.

What is the most elegant in this case of accomplishing this with code that need to be compiled for an Arduino (Mega)?

Pseudo-code demonstrating the setup:

class base{
    base(type1 arg1, type2 arg2){/*do something*/}
};

class derived : base{
    int variable;
    derived(typeA a, typeB b, int c) :
    // if a,b match first scenario:
    base(1, 2) 
    // if a,b match second scenario:
    base(3, 4) 
    // if a,b match third scenario:
    base(1, 4) 
    {
        variable = c;
    }
};
JaMiT
  • 14,422
  • 4
  • 15
  • 31
EXIT_FAILURE
  • 278
  • 1
  • 13
  • 2
    That's a lot of words to confusingly describe something that could have been laid out with a code example. Heck, sometimes just trying to put together the code example you'll find your solution. – Delta_G Aug 08 '20 at 23:31
  • Well, what kind of code do you have in mind? A base class and a derived class with a constructor? Apart from that I would not want to put any code into my original question because that's exactly the part I'm asking for. But if you find my question so confusing, it maybe would be to tell me what's so confusing about it instead of simply downvoting. That way I could clarify what I mean and we both wouldn't have to write comment that aren't very helpful. – EXIT_FAILURE Aug 08 '20 at 23:39
  • 1
    Complaining about downvotes just earned you another downvote. If you want help from this site, work with us and give us enough information to understand the problem. – Mark Ransom Aug 09 '20 at 00:11
  • 3
    @exit you where asked for a code sample to make things less confusing, and proceeded to complain about not being told what is confusing. There are a pile of things unclear in your wall of text that your pseudo code cleared up. When someone asks you to put a bit more effort in, and you respond offended,myes you will be dismised by people. Anyhow, hope my answer proves useful. – Yakk - Adam Nevraumont Aug 09 '20 at 01:11
  • 1
    I think what was so confusing about the text was that it mashed together several concepts into a single tangled mess, the linguistic equivalent of [spaghetti code](https://en.wikipedia.org/wiki/Spaghetti_code). I tried separating things out to make it clearer. I hope I did not change the question in the process. – JaMiT Aug 09 '20 at 04:49

4 Answers4

2

This is a case where a helper function to build derived instances would probably work better for you.

class derived : base{
    int variable;
    derived(char a, char b, int c) : base(a, b), variable(c) { }

public:
    static derived build(int a, int b, int c) {
        if(/* a,b match first scenario */) {
            return dervied("w", "x", c);
        }
        else if(/* a,b match second scenario */) {
            return dervied("x", "y", c);
        }
        else if(/* a,b match third scenario */) {
            return dervied("1", "2", c);
        }
        else {
            throw std::runtime_error("Bad arguments");
        }
    }
};

This lets you analyze any arguments before constructing your derived, and by extension your base.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
  • If I understand your code correctly, this will make a call to the base class constructor and the output of that will be ignored. After that you call the contructor a second time, from you build function, correct? However, unfortunately the arguments have to be exactly right at the first call of the base class constructor since a call with the wrong argument values might cause hardware damage. I will add that information to my main question. – EXIT_FAILURE Aug 09 '20 at 00:28
  • No, this constructs one `derived` per call of `build`. `derived`'s constructor calls `base`'s constructor by passing the `char` arguments along without modification. – Stephen Newell Aug 09 '20 at 00:36
  • Edited the example to show `if`s and make it more clear only one `derived` (and by extension, `base`) are constructed per call. – Stephen Newell Aug 09 '20 at 00:44
  • Ah right, sorry. I overlooked the `static` modifier. I'll give it a try. – EXIT_FAILURE Aug 09 '20 at 00:47
2
class base{
  base(int arg1, int arg2){/*do something*/}
};
template<auto i>
using val_t=std::jntegral_constant<dedktype(i), i>;
template<auto i>
constexpr val_t<i> val={};

class derived : base{
  int variable;
  derived(val_t<0>):base(1,2){}
  derived(val_t<1>):base(3,4){}
  derived(val_t<2>):base(1,4){}
  static derived helper(arg a, arg b, arg c){
    if (case 1) return derived(val<0>);
    if (case 2) return derived(val<1>);
    if (case 3) return derived(val<2>);
  }
public:
  derived(arg a, arg b, arg c) :
    derived(helper(a,b,c))
  {
    variable = c;
  }
};

as an aside, until you posted the pseudo-code, I could not determine what you wanted.

Here we use a helper static function that can have complex logic in it before it picks which ctor to call. We have incomplete ctors that we use to construct our base.

The real ctor calls the helper, then runs its body after the helper constructs the base.

This uses delegating ctors and constexpr template variables from . It could be done in pure . It also uses guaranteed elision from without which you need a copy or move ctor.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

The simplest solution is to pass the arguments to the base ctor in by calculating them before passing in.

Derived::Derived(char x, char y, int a) : Base(x , y) {
variable =a;
}

Otherwise I think you may be able to define a constexpr function that will take your int values and give the chars you want and call that in the ctor.

frazb
  • 76
  • 2
0
class derived: base{
private:
    int variable;
    struct args {type1 arg1;type2 arg2;};
    static args build ( typeA& a, typeB& b );// make the decision
    derived(args&& x, int c)// delegeted only
        :base{std::move(x.arg1),std::move(x.arg2)}
        ,variable(c){};
public:
    derived(typeA a, typeB b, int c)// delegating ctor
        :derived(build(a,b),c){};
};
Red.Wave
  • 2,790
  • 11
  • 17