How to design extensible multiple inheritance?











up vote
0
down vote

favorite












I have yet another question about multiple inheritance design which has an answer i.e. here (but focused on footprint) or here (too vague), but most answers I stumbled upon is emphasizing the performance drawbacks. However (as Bjarne Stroustrup claims here) it is a language feature which should be prefered to workarounds. Here is a longer example to ilustrate the question which follows the example:



The Example



In Czech Republic, the birth number (SSN equivalent) is assigned in this format:
YYMMDDXXX, so let's have a class to get the birth date in standard D.M.YYYY:



class Human {
protected:
char output[11];
char input[10];

public:
Human (const char* number) {
strncpy(input, number, 10);
if(!number[10]) throw E_INVALID_NUMBER;
}

static int twoCharsToNum(const char* str) {
if(!isdigit(str[0]) || !isdigit(str[1])) throw E_INVALID_NUMBER;
return (str[0]-'0')*10 +str[1]-'0';
}

const char* getDate() {
sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
return output;
}

// range check omitted here to make code short
virtual int getDay() { return twoCharsToNum(input+4); }
virtual int getMonth() { return twoCharsToNum(input+2); }
virtual int getYear() { return twoCharsToNum(input)+1900; }
};


Three methods are virtual, because females got +50 to their month. So let's inherit Man and Woman classes to get the date properly:



class Man : public Human {
public:
using Human::Human;
};

class Woman : public Human {
public:
using Human::Human;
int getMonth() {
int result = twoCharsToNum(input+2)-50;
if(result<0) throw E_INVALID_GENDER;
if(result==0 || result>12) throw E_INVALID_RANGE;
return result;
}
};


Since 1954 the number has 4 digits appendix, not 3 (there is a sad story behind this mentioned at the end of this question). If the library was written in 1944, ten years later somebody can write a Facade to get the birth date correctly for future millenials:



class Human2 : public Human {
public:
using Human::Human;
virtual int getYear() {
int year = twoCharsToNum(input);
if(year<54 && strlen(number)==10) year+= 2000;
else year+= 1900;
return year;
}
};

class Man2 : public Human2 {
public:
using Human2::Human2;
};


In class Woman2 we need the Woman::getMonth method, so we need to solve the diamond problem:



class Human2 : virtual public Human { ... };
class Woman : virtual public Human { ... }; // here is the real issue
class Woman2 : public Human2, public Woman {
using Human2::Human2;
using Woman::Woman;
};


The Diamond problem diagram:



    Woman2
^ ^
| |
Woman Human2
^ ^
| |
Human


The Question



The issue is that Human, Man and Woman could be in a form of binary library where the client code can not rewrite the inheritance to virtual. So how to properly design extensible library to enable multiple inheritance? Should I make every inheritance in the library scope virtual (since I don't know in advance how it could be extended), or is there any more elegant universal design?



Regarding the performance: isn't this the domain of low-level programming and compiler optimization, shouldn't the design perspective prevail on high level programming? Why compilers don't auto virtualize inheritance like they do in RVO or inline calls decisions?



The sad story behind the example



In 1954 some technically inspired bureucrat decided that tenth cipher will be added in a way so the number will be divisible by 11. Later the genius figured out that there are numbers which can not be modified this way. So he issued an exception that in these cases the last number will be zero. Later that year an internal directive was issued, that no such exceptions will be allowed. But in the meantime some 1000+ birth numbers were issued which are not divisible by 11, but still legal. Regardless of this mess, the century of the year can be inferred by the number length until 2054, when we will experience Y2K revival. Alas, there is also a common practice that immigrants born before 1964 get assigned a 10-digit birth number.










share|improve this question
























  • The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
    – SergeyA
    6 hours ago










  • Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
    – Jan Turoň
    6 hours ago






  • 2




    I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
    – Galik
    6 hours ago






  • 1




    I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
    – Tim Randall
    6 hours ago






  • 1




    what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
    – AlexG
    5 hours ago

















up vote
0
down vote

favorite












I have yet another question about multiple inheritance design which has an answer i.e. here (but focused on footprint) or here (too vague), but most answers I stumbled upon is emphasizing the performance drawbacks. However (as Bjarne Stroustrup claims here) it is a language feature which should be prefered to workarounds. Here is a longer example to ilustrate the question which follows the example:



The Example



In Czech Republic, the birth number (SSN equivalent) is assigned in this format:
YYMMDDXXX, so let's have a class to get the birth date in standard D.M.YYYY:



class Human {
protected:
char output[11];
char input[10];

public:
Human (const char* number) {
strncpy(input, number, 10);
if(!number[10]) throw E_INVALID_NUMBER;
}

static int twoCharsToNum(const char* str) {
if(!isdigit(str[0]) || !isdigit(str[1])) throw E_INVALID_NUMBER;
return (str[0]-'0')*10 +str[1]-'0';
}

const char* getDate() {
sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
return output;
}

// range check omitted here to make code short
virtual int getDay() { return twoCharsToNum(input+4); }
virtual int getMonth() { return twoCharsToNum(input+2); }
virtual int getYear() { return twoCharsToNum(input)+1900; }
};


Three methods are virtual, because females got +50 to their month. So let's inherit Man and Woman classes to get the date properly:



class Man : public Human {
public:
using Human::Human;
};

class Woman : public Human {
public:
using Human::Human;
int getMonth() {
int result = twoCharsToNum(input+2)-50;
if(result<0) throw E_INVALID_GENDER;
if(result==0 || result>12) throw E_INVALID_RANGE;
return result;
}
};


Since 1954 the number has 4 digits appendix, not 3 (there is a sad story behind this mentioned at the end of this question). If the library was written in 1944, ten years later somebody can write a Facade to get the birth date correctly for future millenials:



class Human2 : public Human {
public:
using Human::Human;
virtual int getYear() {
int year = twoCharsToNum(input);
if(year<54 && strlen(number)==10) year+= 2000;
else year+= 1900;
return year;
}
};

class Man2 : public Human2 {
public:
using Human2::Human2;
};


In class Woman2 we need the Woman::getMonth method, so we need to solve the diamond problem:



class Human2 : virtual public Human { ... };
class Woman : virtual public Human { ... }; // here is the real issue
class Woman2 : public Human2, public Woman {
using Human2::Human2;
using Woman::Woman;
};


The Diamond problem diagram:



    Woman2
^ ^
| |
Woman Human2
^ ^
| |
Human


The Question



The issue is that Human, Man and Woman could be in a form of binary library where the client code can not rewrite the inheritance to virtual. So how to properly design extensible library to enable multiple inheritance? Should I make every inheritance in the library scope virtual (since I don't know in advance how it could be extended), or is there any more elegant universal design?



Regarding the performance: isn't this the domain of low-level programming and compiler optimization, shouldn't the design perspective prevail on high level programming? Why compilers don't auto virtualize inheritance like they do in RVO or inline calls decisions?



The sad story behind the example



In 1954 some technically inspired bureucrat decided that tenth cipher will be added in a way so the number will be divisible by 11. Later the genius figured out that there are numbers which can not be modified this way. So he issued an exception that in these cases the last number will be zero. Later that year an internal directive was issued, that no such exceptions will be allowed. But in the meantime some 1000+ birth numbers were issued which are not divisible by 11, but still legal. Regardless of this mess, the century of the year can be inferred by the number length until 2054, when we will experience Y2K revival. Alas, there is also a common practice that immigrants born before 1964 get assigned a 10-digit birth number.










share|improve this question
























  • The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
    – SergeyA
    6 hours ago










  • Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
    – Jan Turoň
    6 hours ago






  • 2




    I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
    – Galik
    6 hours ago






  • 1




    I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
    – Tim Randall
    6 hours ago






  • 1




    what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
    – AlexG
    5 hours ago















up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have yet another question about multiple inheritance design which has an answer i.e. here (but focused on footprint) or here (too vague), but most answers I stumbled upon is emphasizing the performance drawbacks. However (as Bjarne Stroustrup claims here) it is a language feature which should be prefered to workarounds. Here is a longer example to ilustrate the question which follows the example:



The Example



In Czech Republic, the birth number (SSN equivalent) is assigned in this format:
YYMMDDXXX, so let's have a class to get the birth date in standard D.M.YYYY:



class Human {
protected:
char output[11];
char input[10];

public:
Human (const char* number) {
strncpy(input, number, 10);
if(!number[10]) throw E_INVALID_NUMBER;
}

static int twoCharsToNum(const char* str) {
if(!isdigit(str[0]) || !isdigit(str[1])) throw E_INVALID_NUMBER;
return (str[0]-'0')*10 +str[1]-'0';
}

const char* getDate() {
sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
return output;
}

// range check omitted here to make code short
virtual int getDay() { return twoCharsToNum(input+4); }
virtual int getMonth() { return twoCharsToNum(input+2); }
virtual int getYear() { return twoCharsToNum(input)+1900; }
};


Three methods are virtual, because females got +50 to their month. So let's inherit Man and Woman classes to get the date properly:



class Man : public Human {
public:
using Human::Human;
};

class Woman : public Human {
public:
using Human::Human;
int getMonth() {
int result = twoCharsToNum(input+2)-50;
if(result<0) throw E_INVALID_GENDER;
if(result==0 || result>12) throw E_INVALID_RANGE;
return result;
}
};


Since 1954 the number has 4 digits appendix, not 3 (there is a sad story behind this mentioned at the end of this question). If the library was written in 1944, ten years later somebody can write a Facade to get the birth date correctly for future millenials:



class Human2 : public Human {
public:
using Human::Human;
virtual int getYear() {
int year = twoCharsToNum(input);
if(year<54 && strlen(number)==10) year+= 2000;
else year+= 1900;
return year;
}
};

class Man2 : public Human2 {
public:
using Human2::Human2;
};


In class Woman2 we need the Woman::getMonth method, so we need to solve the diamond problem:



class Human2 : virtual public Human { ... };
class Woman : virtual public Human { ... }; // here is the real issue
class Woman2 : public Human2, public Woman {
using Human2::Human2;
using Woman::Woman;
};


The Diamond problem diagram:



    Woman2
^ ^
| |
Woman Human2
^ ^
| |
Human


The Question



The issue is that Human, Man and Woman could be in a form of binary library where the client code can not rewrite the inheritance to virtual. So how to properly design extensible library to enable multiple inheritance? Should I make every inheritance in the library scope virtual (since I don't know in advance how it could be extended), or is there any more elegant universal design?



Regarding the performance: isn't this the domain of low-level programming and compiler optimization, shouldn't the design perspective prevail on high level programming? Why compilers don't auto virtualize inheritance like they do in RVO or inline calls decisions?



The sad story behind the example



In 1954 some technically inspired bureucrat decided that tenth cipher will be added in a way so the number will be divisible by 11. Later the genius figured out that there are numbers which can not be modified this way. So he issued an exception that in these cases the last number will be zero. Later that year an internal directive was issued, that no such exceptions will be allowed. But in the meantime some 1000+ birth numbers were issued which are not divisible by 11, but still legal. Regardless of this mess, the century of the year can be inferred by the number length until 2054, when we will experience Y2K revival. Alas, there is also a common practice that immigrants born before 1964 get assigned a 10-digit birth number.










share|improve this question















I have yet another question about multiple inheritance design which has an answer i.e. here (but focused on footprint) or here (too vague), but most answers I stumbled upon is emphasizing the performance drawbacks. However (as Bjarne Stroustrup claims here) it is a language feature which should be prefered to workarounds. Here is a longer example to ilustrate the question which follows the example:



The Example



In Czech Republic, the birth number (SSN equivalent) is assigned in this format:
YYMMDDXXX, so let's have a class to get the birth date in standard D.M.YYYY:



class Human {
protected:
char output[11];
char input[10];

public:
Human (const char* number) {
strncpy(input, number, 10);
if(!number[10]) throw E_INVALID_NUMBER;
}

static int twoCharsToNum(const char* str) {
if(!isdigit(str[0]) || !isdigit(str[1])) throw E_INVALID_NUMBER;
return (str[0]-'0')*10 +str[1]-'0';
}

const char* getDate() {
sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
return output;
}

// range check omitted here to make code short
virtual int getDay() { return twoCharsToNum(input+4); }
virtual int getMonth() { return twoCharsToNum(input+2); }
virtual int getYear() { return twoCharsToNum(input)+1900; }
};


Three methods are virtual, because females got +50 to their month. So let's inherit Man and Woman classes to get the date properly:



class Man : public Human {
public:
using Human::Human;
};

class Woman : public Human {
public:
using Human::Human;
int getMonth() {
int result = twoCharsToNum(input+2)-50;
if(result<0) throw E_INVALID_GENDER;
if(result==0 || result>12) throw E_INVALID_RANGE;
return result;
}
};


Since 1954 the number has 4 digits appendix, not 3 (there is a sad story behind this mentioned at the end of this question). If the library was written in 1944, ten years later somebody can write a Facade to get the birth date correctly for future millenials:



class Human2 : public Human {
public:
using Human::Human;
virtual int getYear() {
int year = twoCharsToNum(input);
if(year<54 && strlen(number)==10) year+= 2000;
else year+= 1900;
return year;
}
};

class Man2 : public Human2 {
public:
using Human2::Human2;
};


In class Woman2 we need the Woman::getMonth method, so we need to solve the diamond problem:



class Human2 : virtual public Human { ... };
class Woman : virtual public Human { ... }; // here is the real issue
class Woman2 : public Human2, public Woman {
using Human2::Human2;
using Woman::Woman;
};


The Diamond problem diagram:



    Woman2
^ ^
| |
Woman Human2
^ ^
| |
Human


The Question



The issue is that Human, Man and Woman could be in a form of binary library where the client code can not rewrite the inheritance to virtual. So how to properly design extensible library to enable multiple inheritance? Should I make every inheritance in the library scope virtual (since I don't know in advance how it could be extended), or is there any more elegant universal design?



Regarding the performance: isn't this the domain of low-level programming and compiler optimization, shouldn't the design perspective prevail on high level programming? Why compilers don't auto virtualize inheritance like they do in RVO or inline calls decisions?



The sad story behind the example



In 1954 some technically inspired bureucrat decided that tenth cipher will be added in a way so the number will be divisible by 11. Later the genius figured out that there are numbers which can not be modified this way. So he issued an exception that in these cases the last number will be zero. Later that year an internal directive was issued, that no such exceptions will be allowed. But in the meantime some 1000+ birth numbers were issued which are not divisible by 11, but still legal. Regardless of this mess, the century of the year can be inferred by the number length until 2054, when we will experience Y2K revival. Alas, there is also a common practice that immigrants born before 1964 get assigned a 10-digit birth number.







c++ multiple-inheritance extensibility






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 6 hours ago

























asked 6 hours ago









Jan Turoň

17.7k1579127




17.7k1579127












  • The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
    – SergeyA
    6 hours ago










  • Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
    – Jan Turoň
    6 hours ago






  • 2




    I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
    – Galik
    6 hours ago






  • 1




    I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
    – Tim Randall
    6 hours ago






  • 1




    what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
    – AlexG
    5 hours ago




















  • The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
    – SergeyA
    6 hours ago










  • Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
    – Jan Turoň
    6 hours ago






  • 2




    I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
    – Galik
    6 hours ago






  • 1




    I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
    – Tim Randall
    6 hours ago






  • 1




    what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
    – AlexG
    5 hours ago


















The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
– SergeyA
6 hours ago




The only thing I understood from the question is that Czech republic will likely benefit from revamping their id generation scheme.
– SergeyA
6 hours ago












Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
– Jan Turoň
6 hours ago




Sorry for lengthy example and rather irrelevant sad story at the end (which is hopefully not that distracting), but I readed many anwers and didn't find there anything useful regarding the design.
– Jan Turoň
6 hours ago




2




2




I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
– Galik
6 hours ago




I think "fixing" bugs through inheritance is probably not something that should be designed for if you can avoid it. It is not really the purpose of inheritance and I am pretty sure this is what we are meant to avoid when they tell us to prefer encapsulation over inheritance.
– Galik
6 hours ago




1




1




I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
– Tim Randall
6 hours ago




I think that this is the sort of case where the existence of an inheritance diamond is a sign that inheritance isn't the correct mechanism. I seem to recall Stroustrup warning against a proliferation of classes in cases where other mechanisms might more simply address the problem. In short, it is okay for a method to contain an if, and a class to contain a bool.
– Tim Randall
6 hours ago




1




1




what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
– AlexG
5 hours ago






what kind of operations would you like to do with those identifiers? It feels like a single class can have a hold of the latest version, and you could have methods that try to convert to older formats, to work with older APIs, e.g. TryConvertTo1944Form()
– AlexG
5 hours ago














1 Answer
1






active

oldest

votes

















up vote
0
down vote













If you can not edit the original lib, you can try to solve it by a "mixin", i.e. new facade class is parametrized by their own base class Man or Woman.



For example:



#include <iostream>
#include <system_error>
#include <cstring>
#include <memory>
#include <type_traits>

class Human {
protected:
char output[11];
char input[10];

public:
Human (const char* number) {
memcpy(input, number, 10);
if(!number[10])
throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
}

static int twoCharsToNum(const char* str) {
if(!isdigit(str[0]) || !isdigit(str[1]))
throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
return (str[0]-'0')*10 +str[1]-'0';
}

const char* getDate() {
sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
return output;
}

// range check omitted here to make code short
virtual int getDay() {
return twoCharsToNum(input+4);
}
virtual int getMonth() {
return twoCharsToNum(input+2);
}
virtual int getYear() {
return twoCharsToNum(input)+1900;
}
};

class Man:public Human {
public:
Man(const char* number):
Human(number)
{}
};

class Woman : public Human {
public:
Woman(const char* number):
Human(number)
{}
virtual int getMonth() override {
int result = Human::twoCharsToNum(input+2)-50;
if(result<0)
throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
if(result==0 || result>12)
throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
return result;
}
};

template<class GenderType>
class Human_Century21:public GenderType {
public:

explicit Human_Century21(const char* number):
GenderType(number)
{
// or use std::enabled_if etc
static_assert( std::is_base_of<Human,GenderType>::value, "Gender type must inherit Human" );
}

virtual int getYear() override {
int year = Human::twoCharsToNum(this->input);
if(year<54 && std::strlen(this->input) == 10 )
year += 2000;
else
year += 1900;
return year;
}
};


int main ()
{
auto man = std::make_shared< Human_Century21<Man> >( "530101123" );
std::cout << "Man: [ year: " << man->getYear() << ", month:" << man->getMonth() << " ]" << std::endl;
auto woman = std::make_shared< Human_Century21<Woman> >( "54510112345" );
std::cout << "Woman: [ year: " << woman->getYear() << ", month:" << woman->getMonth() << " ]" << std::endl;
return 0;
}


Output:



Man: [ year: 1953, month:1 ]
Woman: [ year: 1954, month:1 ]


Aniway, you'd better redisign all those classes, IMHO the best option - store date as an integer or std::chrono type(s) and gender as an enumeration field. Provide an additional factory methods to parse date format string, and iject dependecies into only human class.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400751%2fhow-to-design-extensible-multiple-inheritance%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    If you can not edit the original lib, you can try to solve it by a "mixin", i.e. new facade class is parametrized by their own base class Man or Woman.



    For example:



    #include <iostream>
    #include <system_error>
    #include <cstring>
    #include <memory>
    #include <type_traits>

    class Human {
    protected:
    char output[11];
    char input[10];

    public:
    Human (const char* number) {
    memcpy(input, number, 10);
    if(!number[10])
    throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
    }

    static int twoCharsToNum(const char* str) {
    if(!isdigit(str[0]) || !isdigit(str[1]))
    throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
    return (str[0]-'0')*10 +str[1]-'0';
    }

    const char* getDate() {
    sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
    return output;
    }

    // range check omitted here to make code short
    virtual int getDay() {
    return twoCharsToNum(input+4);
    }
    virtual int getMonth() {
    return twoCharsToNum(input+2);
    }
    virtual int getYear() {
    return twoCharsToNum(input)+1900;
    }
    };

    class Man:public Human {
    public:
    Man(const char* number):
    Human(number)
    {}
    };

    class Woman : public Human {
    public:
    Woman(const char* number):
    Human(number)
    {}
    virtual int getMonth() override {
    int result = Human::twoCharsToNum(input+2)-50;
    if(result<0)
    throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
    if(result==0 || result>12)
    throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
    return result;
    }
    };

    template<class GenderType>
    class Human_Century21:public GenderType {
    public:

    explicit Human_Century21(const char* number):
    GenderType(number)
    {
    // or use std::enabled_if etc
    static_assert( std::is_base_of<Human,GenderType>::value, "Gender type must inherit Human" );
    }

    virtual int getYear() override {
    int year = Human::twoCharsToNum(this->input);
    if(year<54 && std::strlen(this->input) == 10 )
    year += 2000;
    else
    year += 1900;
    return year;
    }
    };


    int main ()
    {
    auto man = std::make_shared< Human_Century21<Man> >( "530101123" );
    std::cout << "Man: [ year: " << man->getYear() << ", month:" << man->getMonth() << " ]" << std::endl;
    auto woman = std::make_shared< Human_Century21<Woman> >( "54510112345" );
    std::cout << "Woman: [ year: " << woman->getYear() << ", month:" << woman->getMonth() << " ]" << std::endl;
    return 0;
    }


    Output:



    Man: [ year: 1953, month:1 ]
    Woman: [ year: 1954, month:1 ]


    Aniway, you'd better redisign all those classes, IMHO the best option - store date as an integer or std::chrono type(s) and gender as an enumeration field. Provide an additional factory methods to parse date format string, and iject dependecies into only human class.






    share|improve this answer



























      up vote
      0
      down vote













      If you can not edit the original lib, you can try to solve it by a "mixin", i.e. new facade class is parametrized by their own base class Man or Woman.



      For example:



      #include <iostream>
      #include <system_error>
      #include <cstring>
      #include <memory>
      #include <type_traits>

      class Human {
      protected:
      char output[11];
      char input[10];

      public:
      Human (const char* number) {
      memcpy(input, number, 10);
      if(!number[10])
      throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
      }

      static int twoCharsToNum(const char* str) {
      if(!isdigit(str[0]) || !isdigit(str[1]))
      throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
      return (str[0]-'0')*10 +str[1]-'0';
      }

      const char* getDate() {
      sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
      return output;
      }

      // range check omitted here to make code short
      virtual int getDay() {
      return twoCharsToNum(input+4);
      }
      virtual int getMonth() {
      return twoCharsToNum(input+2);
      }
      virtual int getYear() {
      return twoCharsToNum(input)+1900;
      }
      };

      class Man:public Human {
      public:
      Man(const char* number):
      Human(number)
      {}
      };

      class Woman : public Human {
      public:
      Woman(const char* number):
      Human(number)
      {}
      virtual int getMonth() override {
      int result = Human::twoCharsToNum(input+2)-50;
      if(result<0)
      throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
      if(result==0 || result>12)
      throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
      return result;
      }
      };

      template<class GenderType>
      class Human_Century21:public GenderType {
      public:

      explicit Human_Century21(const char* number):
      GenderType(number)
      {
      // or use std::enabled_if etc
      static_assert( std::is_base_of<Human,GenderType>::value, "Gender type must inherit Human" );
      }

      virtual int getYear() override {
      int year = Human::twoCharsToNum(this->input);
      if(year<54 && std::strlen(this->input) == 10 )
      year += 2000;
      else
      year += 1900;
      return year;
      }
      };


      int main ()
      {
      auto man = std::make_shared< Human_Century21<Man> >( "530101123" );
      std::cout << "Man: [ year: " << man->getYear() << ", month:" << man->getMonth() << " ]" << std::endl;
      auto woman = std::make_shared< Human_Century21<Woman> >( "54510112345" );
      std::cout << "Woman: [ year: " << woman->getYear() << ", month:" << woman->getMonth() << " ]" << std::endl;
      return 0;
      }


      Output:



      Man: [ year: 1953, month:1 ]
      Woman: [ year: 1954, month:1 ]


      Aniway, you'd better redisign all those classes, IMHO the best option - store date as an integer or std::chrono type(s) and gender as an enumeration field. Provide an additional factory methods to parse date format string, and iject dependecies into only human class.






      share|improve this answer

























        up vote
        0
        down vote










        up vote
        0
        down vote









        If you can not edit the original lib, you can try to solve it by a "mixin", i.e. new facade class is parametrized by their own base class Man or Woman.



        For example:



        #include <iostream>
        #include <system_error>
        #include <cstring>
        #include <memory>
        #include <type_traits>

        class Human {
        protected:
        char output[11];
        char input[10];

        public:
        Human (const char* number) {
        memcpy(input, number, 10);
        if(!number[10])
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        }

        static int twoCharsToNum(const char* str) {
        if(!isdigit(str[0]) || !isdigit(str[1]))
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        return (str[0]-'0')*10 +str[1]-'0';
        }

        const char* getDate() {
        sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
        return output;
        }

        // range check omitted here to make code short
        virtual int getDay() {
        return twoCharsToNum(input+4);
        }
        virtual int getMonth() {
        return twoCharsToNum(input+2);
        }
        virtual int getYear() {
        return twoCharsToNum(input)+1900;
        }
        };

        class Man:public Human {
        public:
        Man(const char* number):
        Human(number)
        {}
        };

        class Woman : public Human {
        public:
        Woman(const char* number):
        Human(number)
        {}
        virtual int getMonth() override {
        int result = Human::twoCharsToNum(input+2)-50;
        if(result<0)
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        if(result==0 || result>12)
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        return result;
        }
        };

        template<class GenderType>
        class Human_Century21:public GenderType {
        public:

        explicit Human_Century21(const char* number):
        GenderType(number)
        {
        // or use std::enabled_if etc
        static_assert( std::is_base_of<Human,GenderType>::value, "Gender type must inherit Human" );
        }

        virtual int getYear() override {
        int year = Human::twoCharsToNum(this->input);
        if(year<54 && std::strlen(this->input) == 10 )
        year += 2000;
        else
        year += 1900;
        return year;
        }
        };


        int main ()
        {
        auto man = std::make_shared< Human_Century21<Man> >( "530101123" );
        std::cout << "Man: [ year: " << man->getYear() << ", month:" << man->getMonth() << " ]" << std::endl;
        auto woman = std::make_shared< Human_Century21<Woman> >( "54510112345" );
        std::cout << "Woman: [ year: " << woman->getYear() << ", month:" << woman->getMonth() << " ]" << std::endl;
        return 0;
        }


        Output:



        Man: [ year: 1953, month:1 ]
        Woman: [ year: 1954, month:1 ]


        Aniway, you'd better redisign all those classes, IMHO the best option - store date as an integer or std::chrono type(s) and gender as an enumeration field. Provide an additional factory methods to parse date format string, and iject dependecies into only human class.






        share|improve this answer














        If you can not edit the original lib, you can try to solve it by a "mixin", i.e. new facade class is parametrized by their own base class Man or Woman.



        For example:



        #include <iostream>
        #include <system_error>
        #include <cstring>
        #include <memory>
        #include <type_traits>

        class Human {
        protected:
        char output[11];
        char input[10];

        public:
        Human (const char* number) {
        memcpy(input, number, 10);
        if(!number[10])
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        }

        static int twoCharsToNum(const char* str) {
        if(!isdigit(str[0]) || !isdigit(str[1]))
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        return (str[0]-'0')*10 +str[1]-'0';
        }

        const char* getDate() {
        sprintf(output, "%d.%d.%d", getDay(), getMonth(), getYear());
        return output;
        }

        // range check omitted here to make code short
        virtual int getDay() {
        return twoCharsToNum(input+4);
        }
        virtual int getMonth() {
        return twoCharsToNum(input+2);
        }
        virtual int getYear() {
        return twoCharsToNum(input)+1900;
        }
        };

        class Man:public Human {
        public:
        Man(const char* number):
        Human(number)
        {}
        };

        class Woman : public Human {
        public:
        Woman(const char* number):
        Human(number)
        {}
        virtual int getMonth() override {
        int result = Human::twoCharsToNum(input+2)-50;
        if(result<0)
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        if(result==0 || result>12)
        throw std::system_error( std::make_error_code( std::errc::invalid_argument ) );
        return result;
        }
        };

        template<class GenderType>
        class Human_Century21:public GenderType {
        public:

        explicit Human_Century21(const char* number):
        GenderType(number)
        {
        // or use std::enabled_if etc
        static_assert( std::is_base_of<Human,GenderType>::value, "Gender type must inherit Human" );
        }

        virtual int getYear() override {
        int year = Human::twoCharsToNum(this->input);
        if(year<54 && std::strlen(this->input) == 10 )
        year += 2000;
        else
        year += 1900;
        return year;
        }
        };


        int main ()
        {
        auto man = std::make_shared< Human_Century21<Man> >( "530101123" );
        std::cout << "Man: [ year: " << man->getYear() << ", month:" << man->getMonth() << " ]" << std::endl;
        auto woman = std::make_shared< Human_Century21<Woman> >( "54510112345" );
        std::cout << "Woman: [ year: " << woman->getYear() << ", month:" << woman->getMonth() << " ]" << std::endl;
        return 0;
        }


        Output:



        Man: [ year: 1953, month:1 ]
        Woman: [ year: 1954, month:1 ]


        Aniway, you'd better redisign all those classes, IMHO the best option - store date as an integer or std::chrono type(s) and gender as an enumeration field. Provide an additional factory methods to parse date format string, and iject dependecies into only human class.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 3 hours ago

























        answered 4 hours ago









        Victor Gubin

        1,153111




        1,153111






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400751%2fhow-to-design-extensible-multiple-inheritance%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...