C++ diamond problem - How to call base method only onceWhy should I avoid multiple inheritance in C++?Can I call a constructor from another constructor (do constructor chaining) in C++?How can I profile C++ code running on Linux?Asymmetric virtual Inheritance diamond in C++How to make plugable factory work with lua?Method of derived class needs to downcast its parameterMethod resolution order in C++How to ensure that the assignment operator on a virtual base class is called only once?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?overriding 'virtual void ' c++ errorC++ Compiler doesn't recognize templated diamond
Minor Revision with suggestion of an alternative proof by reviewer
How exactly does Hawking radiation decrease the mass of black holes?
How to creep the reader out with what seems like a normal person?
Is there an official tutorial for installing Ubuntu 18.04+ on a device with an SSD and an additional internal hard drive?
Phrase for the opposite of "foolproof"
How to have a sharp product image?
How do I deal with a coworker that keeps asking to make small superficial changes to a report, and it is seriously triggering my anxiety?
Unexpected email from Yorkshire Bank
What was the first Intel x86 processor with "Base + Index * Scale + Displacement" addressing mode?
How to pronounce 'C++' in Spanish
Does holding a wand and speaking its command word count as V/S/M spell components?
Realistic Necromancy?
What is the strongest case that can be made in favour of the UK regaining some control over fishing policy after Brexit?
How to reduce LED flash rate (frequency)
How to make a pipeline wait for end-of-file or stop after an error?
Map of water taps to fill bottles
Meaning of Bloch representation
Is it possible to determine the symmetric encryption method used by output size?
How to stop co-workers from teasing me because I know Russian?
How to solve constants out of the internal energy equation?
Please, smoke with good manners
Error message with tabularx
Why do Computer Science majors learn Calculus?
How can Republicans who favour free markets, consistently express anger when they don't like the outcome of that choice?
C++ diamond problem - How to call base method only once
Why should I avoid multiple inheritance in C++?Can I call a constructor from another constructor (do constructor chaining) in C++?How can I profile C++ code running on Linux?Asymmetric virtual Inheritance diamond in C++How to make plugable factory work with lua?Method of derived class needs to downcast its parameterMethod resolution order in C++How to ensure that the assignment operator on a virtual base class is called only once?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?overriding 'virtual void ' c++ errorC++ Compiler doesn't recognize templated diamond
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature
/
Swimmer Flier
/
Duck
Which corresponds to
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Flier::print();
Swimmer::print();
std::cout << "I'm a duck" << std::endl;
;
Now this presents a problem - calling the duck's print
method calls its respective base methods, all of which in turn call the Creature::print()
method, so it ends up being called twice-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
c++ multiple-inheritance diamond-problem
|
show 1 more comment
I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature
/
Swimmer Flier
/
Duck
Which corresponds to
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Flier::print();
Swimmer::print();
std::cout << "I'm a duck" << std::endl;
;
Now this presents a problem - calling the duck's print
method calls its respective base methods, all of which in turn call the Creature::print()
method, so it ends up being called twice-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
c++ multiple-inheritance diamond-problem
16
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
2
add (protected)method to your extrastd::cout
, so you can choose which version to call exactly.
– Jarod42
Apr 24 at 12:24
1
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
1
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago
|
show 1 more comment
I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature
/
Swimmer Flier
/
Duck
Which corresponds to
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Flier::print();
Swimmer::print();
std::cout << "I'm a duck" << std::endl;
;
Now this presents a problem - calling the duck's print
method calls its respective base methods, all of which in turn call the Creature::print()
method, so it ends up being called twice-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
c++ multiple-inheritance diamond-problem
I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature
/
Swimmer Flier
/
Duck
Which corresponds to
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Flier::print();
Swimmer::print();
std::cout << "I'm a duck" << std::endl;
;
Now this presents a problem - calling the duck's print
method calls its respective base methods, all of which in turn call the Creature::print()
method, so it ends up being called twice-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
c++ multiple-inheritance diamond-problem
c++ multiple-inheritance diamond-problem
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
asked Apr 24 at 12:14
O. AroestiO. Aroesti
177312
177312
16
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
2
add (protected)method to your extrastd::cout
, so you can choose which version to call exactly.
– Jarod42
Apr 24 at 12:24
1
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
1
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago
|
show 1 more comment
16
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
2
add (protected)method to your extrastd::cout
, so you can choose which version to call exactly.
– Jarod42
Apr 24 at 12:24
1
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
1
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago
16
16
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
2
2
add (protected)method to your extra
std::cout
, so you can choose which version to call exactly.– Jarod42
Apr 24 at 12:24
add (protected)method to your extra
std::cout
, so you can choose which version to call exactly.– Jarod42
Apr 24 at 12:24
1
1
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
1
1
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago
|
show 1 more comment
7 Answers
7
active
oldest
votes
Most likely this is an XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
public:
virtual void identify()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a swimmern";
virtual void tell_ability()
std::cout << "I can swimn";
;
class Flier : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a fliern";
virtual void tell_ability()
std::cout << "I can flyn";
;
class Duck : public Flier, public Swimmer
public:
virtual void tell_ability() override
Flier::tell_ability();
Swimmer::tell_ability();
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a duckn";
;
int main()
Creature c;
c.identify();
std::cout << "------------------n";
Swimmer s;
s.identify();
std::cout << "------------------n";
Flier f;
f.identify();
std::cout << "------------------n";
Duck d;
d.identify();
std::cout << "------------------n";
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
add a comment |
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
public:
std::string const attribute"I'm a creature"s;
std::vector<std::string> attributesattribute;
virtual void print()
for (auto& i : attributes)
std::cout << i << std::endl;
;
class Swimmer : public virtual Creature
public:
Swimmer() attributes.push_back(attribute);
std::string const attribute"I can swim"s;
;
class Flier : public virtual Creature
public:
Flier() attributes.push_back(attribute);
std::string const attribute"I can fly"s;
;
class Duck : public Flier, public Swimmer
public:
Duck() attributes.push_back(attribute);
std::string const attribute"I'm a duck"s;
;
int main()
Duck d;
d.print();
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
public:
std::vector<std::function<void()>> print_functions[this] Creature::print_this(); ;
virtual void print_this()
std::cout << "I'm a creature" << std::endl;
void print()
for (auto& f : print_functions)
f();
;
class Swimmer : public virtual Creature
public:
Swimmer() print_functions.push_back([this] Swimmer::print_this(); );
void print_this()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
Flier() print_functions.push_back([this] Flier::print_this(); );
void print_this()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
Duck() print_functions.push_back([this] Duck::print_this(); );
void print_this()
std::cout << "I'm a duck" << std::endl;
;
int main()
Duck d;
d.print();
1
That makes every instance allocate an entirestd::vector
, which is a bit heavy.
– Kevin
Apr 24 at 19:35
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
|
show 1 more comment
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter
CreaturePrinter()
std::cout << "I'm a creaturen";
;
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
add a comment |
Your explicit calls to the print
methods form the crux of the issue.
One way round this would be to drop the print
calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set
. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature
.
If you want to preserve the order of printing, then you'd need to replace the set
with another container that respects the order of insertion and rejects duplicates.
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
add a comment |
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print
is easy.
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
void detailPrint()
std::cout << "I'm a duck" << std::endl;
;
Without details what is your actual problem is, it hard to come up with a better solution.
add a comment |
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x)
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
;
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Walker : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer, public Walker
public:
void print()
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
;
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant
does not have a portable definition. I wish it were a standard concept.
add a comment |
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
std::cout << "I'm a duck" << std::endl;
;
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
add a comment |
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',
autoActivateHeartbeat: false,
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55829798%2fc-diamond-problem-how-to-call-base-method-only-once%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
Most likely this is an XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
public:
virtual void identify()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a swimmern";
virtual void tell_ability()
std::cout << "I can swimn";
;
class Flier : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a fliern";
virtual void tell_ability()
std::cout << "I can flyn";
;
class Duck : public Flier, public Swimmer
public:
virtual void tell_ability() override
Flier::tell_ability();
Swimmer::tell_ability();
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a duckn";
;
int main()
Creature c;
c.identify();
std::cout << "------------------n";
Swimmer s;
s.identify();
std::cout << "------------------n";
Flier f;
f.identify();
std::cout << "------------------n";
Duck d;
d.identify();
std::cout << "------------------n";
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
add a comment |
Most likely this is an XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
public:
virtual void identify()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a swimmern";
virtual void tell_ability()
std::cout << "I can swimn";
;
class Flier : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a fliern";
virtual void tell_ability()
std::cout << "I can flyn";
;
class Duck : public Flier, public Swimmer
public:
virtual void tell_ability() override
Flier::tell_ability();
Swimmer::tell_ability();
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a duckn";
;
int main()
Creature c;
c.identify();
std::cout << "------------------n";
Swimmer s;
s.identify();
std::cout << "------------------n";
Flier f;
f.identify();
std::cout << "------------------n";
Duck d;
d.identify();
std::cout << "------------------n";
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
add a comment |
Most likely this is an XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
public:
virtual void identify()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a swimmern";
virtual void tell_ability()
std::cout << "I can swimn";
;
class Flier : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a fliern";
virtual void tell_ability()
std::cout << "I can flyn";
;
class Duck : public Flier, public Swimmer
public:
virtual void tell_ability() override
Flier::tell_ability();
Swimmer::tell_ability();
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a duckn";
;
int main()
Creature c;
c.identify();
std::cout << "------------------n";
Swimmer s;
s.identify();
std::cout << "------------------n";
Flier f;
f.identify();
std::cout << "------------------n";
Duck d;
d.identify();
std::cout << "------------------n";
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
Most likely this is an XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
public:
virtual void identify()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a swimmern";
virtual void tell_ability()
std::cout << "I can swimn";
;
class Flier : public virtual Creature
public:
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a fliern";
virtual void tell_ability()
std::cout << "I can flyn";
;
class Duck : public Flier, public Swimmer
public:
virtual void tell_ability() override
Flier::tell_ability();
Swimmer::tell_ability();
virtual void identify() override
Creature::identify();
tell_ability();
std::cout << "I'm a duckn";
;
int main()
Creature c;
c.identify();
std::cout << "------------------n";
Swimmer s;
s.identify();
std::cout << "------------------n";
Flier f;
f.identify();
std::cout << "------------------n";
Duck d;
d.identify();
std::cout << "------------------n";
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
answered Apr 24 at 12:29
SwordfishSwordfish
10.7k11538
10.7k11538
add a comment |
add a comment |
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
public:
std::string const attribute"I'm a creature"s;
std::vector<std::string> attributesattribute;
virtual void print()
for (auto& i : attributes)
std::cout << i << std::endl;
;
class Swimmer : public virtual Creature
public:
Swimmer() attributes.push_back(attribute);
std::string const attribute"I can swim"s;
;
class Flier : public virtual Creature
public:
Flier() attributes.push_back(attribute);
std::string const attribute"I can fly"s;
;
class Duck : public Flier, public Swimmer
public:
Duck() attributes.push_back(attribute);
std::string const attribute"I'm a duck"s;
;
int main()
Duck d;
d.print();
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
public:
std::vector<std::function<void()>> print_functions[this] Creature::print_this(); ;
virtual void print_this()
std::cout << "I'm a creature" << std::endl;
void print()
for (auto& f : print_functions)
f();
;
class Swimmer : public virtual Creature
public:
Swimmer() print_functions.push_back([this] Swimmer::print_this(); );
void print_this()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
Flier() print_functions.push_back([this] Flier::print_this(); );
void print_this()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
Duck() print_functions.push_back([this] Duck::print_this(); );
void print_this()
std::cout << "I'm a duck" << std::endl;
;
int main()
Duck d;
d.print();
1
That makes every instance allocate an entirestd::vector
, which is a bit heavy.
– Kevin
Apr 24 at 19:35
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
|
show 1 more comment
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
public:
std::string const attribute"I'm a creature"s;
std::vector<std::string> attributesattribute;
virtual void print()
for (auto& i : attributes)
std::cout << i << std::endl;
;
class Swimmer : public virtual Creature
public:
Swimmer() attributes.push_back(attribute);
std::string const attribute"I can swim"s;
;
class Flier : public virtual Creature
public:
Flier() attributes.push_back(attribute);
std::string const attribute"I can fly"s;
;
class Duck : public Flier, public Swimmer
public:
Duck() attributes.push_back(attribute);
std::string const attribute"I'm a duck"s;
;
int main()
Duck d;
d.print();
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
public:
std::vector<std::function<void()>> print_functions[this] Creature::print_this(); ;
virtual void print_this()
std::cout << "I'm a creature" << std::endl;
void print()
for (auto& f : print_functions)
f();
;
class Swimmer : public virtual Creature
public:
Swimmer() print_functions.push_back([this] Swimmer::print_this(); );
void print_this()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
Flier() print_functions.push_back([this] Flier::print_this(); );
void print_this()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
Duck() print_functions.push_back([this] Duck::print_this(); );
void print_this()
std::cout << "I'm a duck" << std::endl;
;
int main()
Duck d;
d.print();
1
That makes every instance allocate an entirestd::vector
, which is a bit heavy.
– Kevin
Apr 24 at 19:35
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
|
show 1 more comment
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
public:
std::string const attribute"I'm a creature"s;
std::vector<std::string> attributesattribute;
virtual void print()
for (auto& i : attributes)
std::cout << i << std::endl;
;
class Swimmer : public virtual Creature
public:
Swimmer() attributes.push_back(attribute);
std::string const attribute"I can swim"s;
;
class Flier : public virtual Creature
public:
Flier() attributes.push_back(attribute);
std::string const attribute"I can fly"s;
;
class Duck : public Flier, public Swimmer
public:
Duck() attributes.push_back(attribute);
std::string const attribute"I'm a duck"s;
;
int main()
Duck d;
d.print();
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
public:
std::vector<std::function<void()>> print_functions[this] Creature::print_this(); ;
virtual void print_this()
std::cout << "I'm a creature" << std::endl;
void print()
for (auto& f : print_functions)
f();
;
class Swimmer : public virtual Creature
public:
Swimmer() print_functions.push_back([this] Swimmer::print_this(); );
void print_this()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
Flier() print_functions.push_back([this] Flier::print_this(); );
void print_this()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
Duck() print_functions.push_back([this] Duck::print_this(); );
void print_this()
std::cout << "I'm a duck" << std::endl;
;
int main()
Duck d;
d.print();
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
public:
std::string const attribute"I'm a creature"s;
std::vector<std::string> attributesattribute;
virtual void print()
for (auto& i : attributes)
std::cout << i << std::endl;
;
class Swimmer : public virtual Creature
public:
Swimmer() attributes.push_back(attribute);
std::string const attribute"I can swim"s;
;
class Flier : public virtual Creature
public:
Flier() attributes.push_back(attribute);
std::string const attribute"I can fly"s;
;
class Duck : public Flier, public Swimmer
public:
Duck() attributes.push_back(attribute);
std::string const attribute"I'm a duck"s;
;
int main()
Duck d;
d.print();
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
public:
std::vector<std::function<void()>> print_functions[this] Creature::print_this(); ;
virtual void print_this()
std::cout << "I'm a creature" << std::endl;
void print()
for (auto& f : print_functions)
f();
;
class Swimmer : public virtual Creature
public:
Swimmer() print_functions.push_back([this] Swimmer::print_this(); );
void print_this()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
Flier() print_functions.push_back([this] Flier::print_this(); );
void print_this()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
Duck() print_functions.push_back([this] Duck::print_this(); );
void print_this()
std::cout << "I'm a duck" << std::endl;
;
int main()
Duck d;
d.print();
edited Apr 24 at 19:14
answered Apr 24 at 12:25
wallywally
7,31532346
7,31532346
1
That makes every instance allocate an entirestd::vector
, which is a bit heavy.
– Kevin
Apr 24 at 19:35
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
|
show 1 more comment
1
That makes every instance allocate an entirestd::vector
, which is a bit heavy.
– Kevin
Apr 24 at 19:35
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
1
1
That makes every instance allocate an entire
std::vector
, which is a bit heavy.– Kevin
Apr 24 at 19:35
That makes every instance allocate an entire
std::vector
, which is a bit heavy.– Kevin
Apr 24 at 19:35
6
6
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@Kevin I'm guessing you won't like vtables either. :)
– wally
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
@wally vtables involve storing a pointer to a bit of read-only memory - can often be done in a single move instruction. Vectors involve allocating memory from the heap, which is going to involve grabbing and releasing a mutex, with all the memory barrier and cache-flushing that implies.
– Martin Bonner
2 days ago
1
1
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
@MartinBonner Other threads wouldn't have access to the object until after construction. Why would you need to lock a mutex for the vector? And where did you hear that you need a mutex for heap allocation?
– wally
2 days ago
1
1
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
@MartinBonner If you're referring to the locking that the operating system does then it is unavoidable. I suppose that if you create the vector with the correct size then the extra malloc might be optimized away if you're creating the entire object on the heap anyway. The contention between threads might also be reduced if the OS decided to use separate arenas for the allocations. The OS might also not be using a mutex. In general, defensively designing around this would be impractical. std::vector is not that bad.
– wally
2 days ago
|
show 1 more comment
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter
CreaturePrinter()
std::cout << "I'm a creaturen";
;
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
add a comment |
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter
CreaturePrinter()
std::cout << "I'm a creaturen";
;
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
add a comment |
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter
CreaturePrinter()
std::cout << "I'm a creaturen";
;
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter
CreaturePrinter()
std::cout << "I'm a creaturen";
;
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
edited Apr 24 at 14:23
answered Apr 24 at 14:18
n.m.n.m.
74.5k885173
74.5k885173
add a comment |
add a comment |
Your explicit calls to the print
methods form the crux of the issue.
One way round this would be to drop the print
calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set
. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature
.
If you want to preserve the order of printing, then you'd need to replace the set
with another container that respects the order of insertion and rejects duplicates.
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
add a comment |
Your explicit calls to the print
methods form the crux of the issue.
One way round this would be to drop the print
calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set
. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature
.
If you want to preserve the order of printing, then you'd need to replace the set
with another container that respects the order of insertion and rejects duplicates.
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
add a comment |
Your explicit calls to the print
methods form the crux of the issue.
One way round this would be to drop the print
calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set
. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature
.
If you want to preserve the order of printing, then you'd need to replace the set
with another container that respects the order of insertion and rejects duplicates.
Your explicit calls to the print
methods form the crux of the issue.
One way round this would be to drop the print
calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set
. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature
.
If you want to preserve the order of printing, then you'd need to replace the set
with another container that respects the order of insertion and rejects duplicates.
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
answered Apr 24 at 12:26
BathshebaBathsheba
183k27257385
183k27257385
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
add a comment |
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
2
2
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
this doesn't solve the problem in general
– sudo rm -rf slash
Apr 24 at 16:29
add a comment |
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print
is easy.
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
void detailPrint()
std::cout << "I'm a duck" << std::endl;
;
Without details what is your actual problem is, it hard to come up with a better solution.
add a comment |
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print
is easy.
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
void detailPrint()
std::cout << "I'm a duck" << std::endl;
;
Without details what is your actual problem is, it hard to come up with a better solution.
add a comment |
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print
is easy.
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
void detailPrint()
std::cout << "I'm a duck" << std::endl;
;
Without details what is your actual problem is, it hard to come up with a better solution.
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print
is easy.
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
Creature::print();
detailPrint();
void detailPrint()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
void print()
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
void detailPrint()
std::cout << "I'm a duck" << std::endl;
;
Without details what is your actual problem is, it hard to come up with a better solution.
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
answered Apr 24 at 14:35
Marek RMarek R
13.9k22778
13.9k22778
add a comment |
add a comment |
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x)
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
;
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Walker : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer, public Walker
public:
void print()
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
;
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant
does not have a portable definition. I wish it were a standard concept.
add a comment |
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x)
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
;
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Walker : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer, public Walker
public:
void print()
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
;
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant
does not have a portable definition. I wish it were a standard concept.
add a comment |
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x)
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
;
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Walker : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer, public Walker
public:
void print()
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
;
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant
does not have a portable definition. I wish it were a standard concept.
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x)
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
;
class Creature
public:
virtual void print()
std::cout << "I'm a creature" << std::endl;
;
class Walker : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
;
class Swimmer : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
void print()
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer, public Walker
public:
void print()
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
;
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant
does not have a portable definition. I wish it were a standard concept.
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
answered Apr 24 at 18:26
Red.WaveRed.Wave
94337
94337
add a comment |
add a comment |
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
std::cout << "I'm a duck" << std::endl;
;
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
add a comment |
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
std::cout << "I'm a duck" << std::endl;
;
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
add a comment |
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
std::cout << "I'm a duck" << std::endl;
;
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can swim" << std::endl;
;
class Flier : public virtual Creature
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
std::cout << "I can fly" << std::endl;
;
class Duck : public Flier, public Swimmer
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
std::cout << "I'm a duck" << std::endl;
;
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
edited 2 days ago
Peter Mortensen
14k1987114
14k1987114
answered 2 days ago
sebrockmsebrockm
1,8751320
1,8751320
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55829798%2fc-diamond-problem-how-to-call-base-method-only-once%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
16
Both Flier and Swimmer's print explicitly calls Creature's print. If I were you I would make an attempt to solve the problem without this inheritance. "Composition over inheritance." For example ECS (entity component system) is exactly about to put properties together in a flexible way without the inheritance hell.
– titapo
Apr 24 at 12:23
2
add (protected)method to your extra
std::cout
, so you can choose which version to call exactly.– Jarod42
Apr 24 at 12:24
1
@titapo that is a good suggestion, please post it as an answer instead of a comment.
– Captain Man
Apr 24 at 19:24
1
As other people posted solutions already, I'd like to emphasize here, that you do not really want to use multiple inheritance and especially a diamond inheritance at all: stackoverflow.com/questions/406081/…
– Lukas Plazovnik
Apr 24 at 20:24
I use multiple inheritances ALL the time professionally. It's not a bad thing, just that most people don't understand the repercussions of multiple inheritances and how to avoid digging yourself into a hole. It's wonderful for MVC and all manner of GUI stuff!
– Bill Smith
2 days ago