O. *_*sti 37 c++ multiple-inheritance diamond-problem
我在C ++中使用多重继承,并通过显式调用基本方法来扩展基本方法。假定以下层次结构:
Creature
/ \
Swimmer Flier
\ /
Duck
Run Code Online (Sandbox Code Playgroud)
对应于
Creature
/ \
Swimmer Flier
\ /
Duck
Run Code Online (Sandbox Code Playgroud)
现在,这带来了一个问题-调用duck的print方法将调用其各自的基本方法,所有这些方法都依次调用该Creature::print()方法,因此最终被两次调用-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
Run Code Online (Sandbox Code Playgroud)
我想找到一种方法来确保基本方法仅被调用一次。与虚拟继承的工作方式类似(在第一次调用时调用基本构造函数,然后仅在来自其他派生类的后续调用中为其分配一个指针)。
是否有一些内置方法可以做到这一点,还是我们需要依靠自己实现?
如果是这样,您将如何处理?
这个问题并非特定于打印。我想知道是否有一种机制可以扩展基本方法和功能,同时保持调用顺序并避免出现钻石问题。
我现在知道,最突出的解决方案是添加辅助方法,但是我只是想知道是否存在“更清洁”的方法。
Swo*_*ish 50
这很可能是XY问题。但是...只是不要再打两次。
#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 swimmer\n";
}
virtual void tell_ability()
{
std::cout << "I can swim\n";
}
};
class Flier : public virtual Creature
{
public:
virtual void identify() override
{
Creature::identify();
tell_ability();
std::cout << "I'm a flier\n";
}
virtual void tell_ability()
{
std::cout << "I can fly\n";
}
};
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 duck\n";
}
};
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";
}
Run Code Online (Sandbox Code Playgroud)
#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 swimmer\n";
}
virtual void tell_ability()
{
std::cout << "I can swim\n";
}
};
class Flier : public virtual Creature
{
public:
virtual void identify() override
{
Creature::identify();
tell_ability();
std::cout << "I'm a flier\n";
}
virtual void tell_ability()
{
std::cout << "I can fly\n";
}
};
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 duck\n";
}
};
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";
}
Run Code Online (Sandbox Code Playgroud)
wal*_*lly 22
我们可以让基类跟踪属性:
#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> attributes{attribute};
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();
}
Run Code Online (Sandbox Code Playgroud)
同样,如果不仅仅是打印,而是函数调用,那么我们可以让基类跟踪函数:
#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();
}
Run Code Online (Sandbox Code Playgroud)
一种简单的方法是创建一堆帮助程序类,以模仿主层次结构的继承结构,并在其构造函数中进行所有打印。
struct CreaturePrinter {
CreaturePrinter() {
std::cout << "I'm a creature\n";
}
};
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Run Code Online (Sandbox Code Playgroud)
然后,主层次结构中的每个打印方法都将创建相应的帮助程序类。没有手动链接。
为了便于维护,您可以将每个打印机类嵌套在其相应的主类中。
自然,在大多数实际情况下,您希望将对主对象的引用作为参数传递给其辅助函数的构造函数。
您对这些print方法的显式调用构成了问题的症结。
解决此问题的一种方法是挂断print电话,并用语音替换
void queue(std::set<std::string>& data)
Run Code Online (Sandbox Code Playgroud)
并且您将打印消息累积到中set。然后,层次结构中的那些函数被多次调用并不重要。
然后,您可以在中的单个方法中实现打印集Creature。
如果要保留打印顺序,则需要set用另一个尊重插入顺序并拒绝重复项的容器替换。
如果要使用该中级方法,请不要调用基类方法。最简单最简单的方法是提取其他方法,然后重新实现Print很容易。
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;
}
};
Run Code Online (Sandbox Code Playgroud)
没有细节,您的实际问题是,很难找到更好的解决方案。
您要求在函数级别上进行类似于继承的操作,它会自动调用继承的函数并仅添加更多代码。您还希望它以虚拟方式完成,就像类继承一样。伪语法:
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;
}
};
Run Code Online (Sandbox Code Playgroud)
所以你的问题的答案
有一些内置的方法可以做到这一点吗?
没有。 C++ 中不存在这样的东西。另外,我不知道任何其他语言有类似的东西。但这是一个有趣的想法......