C++ 为什么重复继承/重复继承无效?
此代码无效:C++ 为什么重复继承/重复继承无效?,c++,inheritance,multiple-inheritance,language-lawyer,C++,Inheritance,Multiple Inheritance,Language Lawyer,此代码无效: struct Agent {}; struct DoubleAgent : public Agent, public Agent {}; 因为: > g++ -c DoubleAgent.cpp DoubleAgent.cpp:2:43: error: duplicate base type ‘Agent’ invalid struct DoubleAgent : public Agent, public Agent {};
struct Agent {};
struct DoubleAgent : public Agent, public Agent {};
因为:
> g++ -c DoubleAgent.cpp
DoubleAgent.cpp:2:43: error: duplicate base type ‘Agent’ invalid
struct DoubleAgent : public Agent, public Agent {};
^
为什么?
我不认为这违反了继承的概念;如果一个类可以与基类有is-a关系,那么它不应该与基类有is-two-of-a关系吗?特别是考虑到C++支持多重继承,一个类已经可以<强> > < /强>多个不同的基类型。
此外,所谓的基类已经间接地支持了这一点,其中多个(不同的)基类可以从公共基类继承
我从维基百科中找到了几句话,似乎暗示这是OO语言中常见但不普遍的约束,可能只是因为担心语法复杂性,这是一个不受欢迎的约束:
设计约束 在设计程序时广泛使用继承会施加某些约束
例如,考虑一个包含人名的类人, 出生日期、地址和电话号码。我们可以定义 名为Student的人员,包含该人员的平均分数 类,还有另一个叫做Employee的子类 包含此人的职务、雇主和工资
在定义这个继承层次结构时,我们已经定义了某些 限制,并非所有限制都是可取的:- 单一性:使用单一继承,子类只能从一个超类继承。继续上面给出的示例,Person 可以是学生也可以是员工,但不能同时是学生和员工。使用多个 继承部分地解决了这个问题,因为可以定义 从Student和Employee继承的StudentEmployee类。 但是,在大多数实现中,它仍然可以从每个 超类只有一次,因此不支持 学生有两份工作或就读两所学校。遗产 埃菲尔铁塔提供的模型通过支持 重复遗传
C++不支持显式重复继承,因为无法限定要使用哪个超类(即,让一个类在单个派生列表中出现多次[类Dog:public Animal,Animal])
我不同意这种说法“……因为没有办法限定使用哪个超类”。编译器不能只允许对基本限定符进行某种类型的索引,例如
Animal[1]::method()
(同样,也可以允许将类定义中的重复折叠为struct DoubleAgent:public Agent[2]{};
)?我看不出有什么问题,从语法和概念上来说,这不是一个非常简单的解决方案吗
我相信我已经找到了一些可能的解决方法,尽管我不能确定它们是否会在实际系统中工作,或者它们是否会导致无法克服的问题:
1:消除基类上模板非类型参数的歧义。
template<int N> struct Agent {};
struct DoubleAgent : public Agent<1>, public Agent<2> {};
正如您所看到的,Agent[N]
基本上本身就是一个类型名,但只有在限定或强制转换具有基础类型的N+1
或更多实例的类型时才有效。这给语言增加了很少的复杂性,这是非常直观的(在我看来),因为它反映了程序员已经熟悉的数组索引,并且我相信它是包罗万象的(即没有留下任何歧义)
回答者似乎面临的主要困难如下:
DoubleAgent spy;
spy.AgentFromSouth::salary = 10000.0;
spy.AgentFromNorth::salary = 800.0;
Agent
和Agent
),如果不需要的话(如果我错了,请纠正我;编译器是否足够聪明,知道类定义中没有使用模板参数,因此它不会为该参数的每个不同参数生成单独的代码?)Edit:这里是另一种可能的语法,我实际上更喜欢这种语法。它允许超类型名称作为成员访问,这有点像:
struct Person { int height; };
struct Agent { int id; };
struct TripleAgent : public Person, public Agent[3] {};
int main() {
TripleAgent tripleAgent;
tripleAgent.Person.height = 42;
tripleAgent.Agent[0].id = 1;
tripleAgent.Agent[1].id = 2;
tripleAgent.Agent[2].id = 3;
Person& person = tripleAgent.Person;
Agent& agent0 = tripleAgent.Agent[0];
Agent& agent1 = tripleAgent.Agent[1];
Agent& agent2 = tripleAgent.Agent[2];
}
我不同意这种说法“……因为没有办法限定使用哪个超类”
当他们说“无法限定要使用哪个超类”时,他们的意思是“如果不发明额外的语法,就无法限定要使用哪个超类”假设它是一个数组就是这样一种发明出来的语法;例如,你可以发明无数与其他语法结构不同的语法
Animal@::method() // @ means "first"
Animal@@::method() // @@ means "second"
我的语法看起来完全是武断的,但你的也一样
当然,通过使语言更加复杂,也可以有其他不太离谱的方法来解决这个问题。然而,关键问题是,使语言更加复杂会带来什么好处
Animal@::method() // @ means "first"
Animal@@::method() // @@ means "second"
class Agent{... std::string loyality;};
class PrimaryRole : public Agent {};
class SecondaryRole : public Agent{};
class DoubleAgent : public PrimaryRole, public SecondaryRole
{
void setLoyalities()
{
PrimaryRole::loyality = "GoodGuys";
SecondaryRole::loyality = "BadGuys";
}
};
class DoubleAgent : public Agent, public SecondaryRole {...};
struct DoubleAgent : public Agent, public Agent {}; // direct base class more than once !!!
struct Agent { double salary; };
struct AgentFromSouth : public Agent {};
struct AgentFromNorth : public Agent {};
struct DoubleAgent : public AgentFromSouth, public AgentFromNorth {}; // valid
DoubleAgent spy;
spy.AgentFromSouth::salary = 10000.0;
spy.AgentFromNorth::salary = 800.0;
DoubleAgent *pspy = ....;
Agent *p = pspy; // ambiguous: which role should I use ? Agent<1> or Agent<2> ?
Agent<1> *p = pspy;
class QuadrupleAgent : DoubleAgent, DoubleAgent {...};
QuadrupleAgend *pmasterspy;
Agent<1> *p = pmasterspy; // Ambiguous: is it DoubleAgent<1>::Agent<1> or DoubleAgent<2>::Agent<1> ?
struct Agent
{
int height;
};
struct DoubleAgent: Agent, Agent
{
};
int main()
{
DoubleAgent a;
a.height = 42; // this would be ambiguous
}
a.Agent::height = 42;
struct TripleAgent: Agent, Agent, Agent
{
};
struct QuadrupleAgent: Agent, Agent, Agent, Agent
{
};
// etc etc