除了教科书示例 - 在现实世界中 - 在C++中使用多重继承(其中多个基类不是纯接口)是否有意义?
我理解C++虚拟继承的基础知识.但是,我很困惑我需要在virtual复杂的类层次结构中使用关键字.例如,假设我有以下类:
A
/ \
B C
/ \ / \
D E F
\ / \ /
G H
\ /
I
Run Code Online (Sandbox Code Playgroud)
如果我想确保在任何子类中都没有出现过多次类,那么需要标记哪些基类virtual?他们都是?或者只在那些直接从一个类派生的类上使用它就足够了,否则这个类可能有多个实例(即B,C,D,E和F;以及G和H(但只有基类E,而不是基类D和F))?
(事先原谅noob问题)
我有4个班:
class Person {};
class Student : public Person {};
class Employee : public Person {};
class StudentEmployee : public Student, public Employee {};
Run Code Online (Sandbox Code Playgroud)
基本上Person是基类,其直接由两个子类Student和Employee.StudentEmployee使用多重继承来子类化Student和Employee.
Person pat = Person("Pat");
Student sam = Student("Sam");
Employee em = Employee("Emily");
StudentEmployee sen = StudentEmployee("Sienna");
Person ppl[3] = {pat, sam, em};
//compile time error: ambiguous base class
//Person ppl[4] = {pat, sam, em, sen};
Run Code Online (Sandbox Code Playgroud)
当我使用Person基类的数组时,我可以将Person它的所有子类放在这个数组中.除了StudentEmployee,给出基础模糊的原因. …
为什么在编译器下面的代码中抱怨这PureAbstractBase是一个模糊的基类MultiplyInheritedClass?我意识到我有两个PureAbstractBasein MultiplyInheritedClass和that的副本,FirstConreteClass并且SecondConreteClass应该实际上派生,因为它们是钻石的中间行(这确实解决了下面代码的问题).但即使我有两个接口副本,为什么代码中的代码MultiplyInheritedClass不仅仅覆盖它们并且明确地选择了定义的接口类MultiplyInheritedClass?
#include <iostream>
using namespace std;
class PureAbstractBase {
public:
virtual void interface() = 0;
};
// I know that changing the following line to:
// class FirstConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object FirstConcreteClass\n"; } …Run Code Online (Sandbox Code Playgroud) #include <iostream>
struct B1
{
virtual void method()=0;
virtual ~B1(){}
};
struct B2
{
virtual void method()=0;
virtual ~B2(){}
};
struct D: B1, B2
{
virtual void method()
{
std::cout << "D::method\n";
};
};
int main(int argc,char *argv[])
{
D d;
B1 &b1=d;
B2 &b2=d;
b1.method();
b2.method();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意,B1和B2不共享通用接口.
这合法吗?如果是 - 在哪个标准?C++ 98/03/11?
msvc和gcc都编译好了.
以前我想过,我必须使用一些通用接口来处理这种情况(可能的虚拟继承).
这种情况有什么特别的名字吗?
请问它的工作原理如何?也许一些ISO参考?
是否有可能有一些抽象接口的部分实现,然后通过使用多个继承将这些部分实现收集到一个具体的类中?
我有以下示例代码:
#include <iostream>
struct Base
{
virtual void F1() = 0;
virtual void F2() = 0;
};
struct D1 : Base
{
void F1() override { std::cout << __func__ << std::endl; }
};
struct D2 : Base
{
void F2() override { std::cout << __func__ << std::endl; }
};
// collection of the two partial implementations to form the concrete implementation
struct Deriv : D1, D2
{
using D1::F1; // I …Run Code Online (Sandbox Code Playgroud) 我经常想要创建一个对象列表,其中每个对象必须实现许多接口.例如,我想做类似以下的事情:
List<T> where T : IConvertible, IComparable _myList;
Run Code Online (Sandbox Code Playgroud)
我考虑的另一个选项是创建一个实现这两个接口的第三个接口,以便实现这两个接口的任何对象本身都实现了我的.
public interface IConvertibleAndComparable
: IConvertible, IComparable { }
List<IConvertibleAndComparable> _myList;
Run Code Online (Sandbox Code Playgroud)
有了这个,我就能够添加同时实现任何物体IConvertible和IComparable,包括double和int,以及我自己的对象.IConvertibleAndComparable不需要显式实现,因为它不会在继承中的接口之外添加任何新功能.
我知道第一个片段是非法的,第二个是合法的,不符合我的要求.是否有可能实现我想做的事情?如果没有,这些中的任何一个都会成为未来C#功能的候选者吗?
(注意:这将是空接口的合法应用程序.)
编辑
在更一般的意义上,我想执行以下操作之一:
private MyGenericClass<T> where T : IA, IB, ... _myClass;
Run Code Online (Sandbox Code Playgroud)
我可以在哪里声明T我需要的所有限制,或者
public interface IMyCombinedInterface : IA, IB, ... {}
private MyGenericClass<IMyCombinedInterface> _myClass;
Run Code Online (Sandbox Code Playgroud)
任何实现IA,IB以及...固有(或隐式)实现的类型IMyCombinedInterface(仅当IMyCombinedInterface未明确声明新功能时).
我在使用boost enable_shared_from_this和多重继承时遇到了一些麻烦.
该场景可以描述如下:
类A实现了一些功能,应该继承enable_shared_from_this
类B实现了另一个功能,应该继承enable_shared_from_this
类D从A和B(class D : public A, public B {})继承功能
当我B从类中使用一些类功能时,D我得到了一个异常(bad_weak_ptr)
继承enable_shared_from_this课程D对我来说不是一个选择
我不知道如何解决这个问题.
哦,我正在使用Visual C++ 2010.
在英语中,同形异义词对是两个具有相同拼写但含义不同的单词.
在软件工程中,一对同形方法是两种具有相同名称但要求不同的方法.让我们看一个人为的例子,让问题尽可能清晰:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
Run Code Online (Sandbox Code Playgroud)
我该如何实施I12?C#有办法做到这一点,但Java没有.所以唯一的方法是破解.怎样才能最可靠地使用反射/字节码技巧/等(也就是说它不一定是一个完美的解决方案,我只想要一个效果最好的解决方案)?
请注意,我无法合法反向工程的一些现有的闭源大量遗留代码需要一个类型参数,I12并将I12两者都委托给I1作为参数的代码和作为参数的代码I2.所以基本上我需要让它的一个实例I12知道什么时候它应该起作用I1,什么时候它应该起作用I2,我相信可以通过在直接调用者的运行时查看字节码来完成.我们可以假设调用者没有使用反射,因为这是简单的代码.问题是作者I12没想到Java会f从两个接口合并,所以现在我必须想出最好的解决问题的方法.没有什么叫I12.f(显然如果作者写了一些实际调用的代码I12.f,他会在出售之前注意到这个问题).
请注意,我实际上是在寻找这个问题的答案,而不是如何重构我无法改变的代码.我正在寻找可行的最佳启发式或者如果存在的话,可以找到精确的解决方案.请参阅Gray的答案以获得有效示例(我确信有更强大的解决方案).
这是一个具体的例子,说明两个接口内的单应方法问题是如何发生的.这是另一个具体的例子:
我有以下6个简单的类/接口.它类似于剧院周围的商业和在其中表演的艺术家.为了简单起见,我们假设它们都是由不同的人创建的.
Set 代表一组,如集合论:
interface Set {
/** Complements this set,
i.e: all elements in the set …Run Code Online (Sandbox Code Playgroud) 我有这个代码(钻石问题):
#include <iostream>
using namespace std;
struct Top
{
void print() { cout << "Top::print()" << endl; }
};
struct Right : Top
{
void print() { cout << "Right::print()" << endl; }
};
struct Left : Top
{
void print() { cout << "Left::print()" << endl; }
};
struct Bottom: Right, Left{};
int main()
{
Bottom b;
b.Right::Top::print();
}
Run Code Online (Sandbox Code Playgroud)
我想print()在Top课堂上打电话.
当我尝试编译它时,我得到错误:'Top' is an ambiguous base of 'Bottom'在这一行:b.Right::Top::print();
为什么它不明确?我明确规定,我想Top从Right与不从 …
c++ ×8
inheritance ×5
c# ×1
hierarchy ×1
interface ×1
java ×1
overriding ×1
polymorphism ×1
shared-ptr ×1
virtual ×1