C++ C++;从具有相同虚拟函数名的多个基类继承
我尝试了以下代码:C++ C++;从具有相同虚拟函数名的多个基类继承,c++,function,class,virtual,multiple-inheritance,C++,Function,Class,Virtual,Multiple Inheritance,我尝试了以下代码: class A { virtual void foo() = 0; }; class B { virtual void foo() = 0; }; class C : public A, public B { //virtual void A::foo(){} //virtual void B::foo(){} virtual void A::foo(); virtual void B::foo(); }; void C
class A
{
virtual void foo() = 0;
};
class B
{
virtual void foo() = 0;
};
class C : public A, public B
{
//virtual void A::foo(){}
//virtual void B::foo(){}
virtual void A::foo();
virtual void B::foo();
};
void C::A::foo(){}
void C::B::foo(){}
int main()
{
C c;
return 0;
}
使用注释的部分是可以的,但是当我尝试在类声明之外编写定义时,编译器会报告错误。
我使用的是MSVC11编译器,有人知道怎么写吗?
我需要将代码移到cpp文件中
谢谢~~您只有一个虚拟函数
foo
:
class A {
virtual void foo() = 0;
};
class B {
virtual void foo() = 0;
};
class C : public A, public B {
virtual void foo();
};
void C::foo(){}
void C::A::foo(){}
void C::B::foo(){};
int main() {
C c;
return 0;
}
函数根据名称和参数类型重写基类的虚拟函数(请参见下文)。因此,类
C
有两个虚拟函数foo
,分别从A
和B
继承一个。但是一个函数void C::foo()
会覆盖这两个函数:
[class.virtual]/2
如果虚拟成员函数vf
在类Base
中声明,并且在直接或间接从Base
派生的类中声明,则声明与Base::vf
具有相同名称、参数类型列表、cv限定和ref限定符(或不存在相同)的成员函数vf
,然后,Derived::vf
也是虚拟的(无论是否如此声明),它覆盖了Base::vf
正如我在评论中已经指出的,[dcl.means]/1禁止在(成员)函数声明中使用限定id:
当声明符id被限定时,声明应引用该限定符所引用的类或命名空间的先前声明的成员[…]”
因此,任何virtualvoid X::foo();
作为C
中的声明都是非法的
代码
class C : public A, public B
{
virtual void foo();
};
是AFAIK重写foo
的唯一方法,它将同时重写A::foo
和B::foo
。对于A::foo
和B::foo
,除了引入另一层继承之外,没有其他不同行为的两种不同重写:
#include <iostream>
struct A
{
virtual void foo() = 0;
};
struct B
{
virtual void foo() = 0;
};
struct CA : A
{
virtual void foo() { std::cout << "A" << std::endl; }
};
struct CB : B
{
virtual void foo() { std::cout << "B" << std::endl; }
};
struct C : CA, CB {};
int main() {
C c;
//c.foo(); // ambiguous
A& a = c;
a.foo();
B& b = c;
b.foo();
}
#包括
结构A
{
虚拟void foo()=0;
};
结构B
{
虚拟void foo()=0;
};
结构CA:A
{
virtual void foo(){std::cout我遇到了同样的问题,并意外地打开了第二个线程。对此感到抱歉。一种对我有效的方法是在不使用多重继承的情况下解决它
#include <stdio.h>
class A
{
public:
virtual void foo(void) = 0;
};
class B
{
public:
virtual void foo(void) = 0;
};
class C
{
class IA: public A
{
virtual void foo(void)
{
printf("IA::foo()\r\n");
}
};
class IB: public B
{
virtual void foo(void)
{
printf("IB::foo()\r\n");
}
};
IA m_A;
IB m_B;
public:
A* GetA(void)
{
return(&m_A);
}
B* GetB(void)
{
return(&m_B);
}
};
…关于foo方法不再有任何歧义。您可以使用不同的函数参数来解决这种歧义
在实际代码中,此类虚拟函数会执行某些操作,因此它们通常已经具有以下两种功能之一:
A和B中的不同参数,或
A和B中的不同返回值可以转换为[out]参数以解决此继承问题;否则
您需要添加一些标记参数,优化器将丢弃这些参数
(在我自己的代码中,我通常发现自己出现在第(1)种情况下,有时出现在第(2)种情况下,到目前为止从未出现在第(3)种情况下。)
您的示例是案例(3),如下所示:
class A
{
public:
struct tag_a { };
virtual void foo(tag_a) = 0;
};
class B
{
public:
struct tag_b { };
virtual void foo(tag_b) = 0;
};
class C : public A, public B
{
void foo(tag_a) override;
void foo(tag_b) override;
};
注释部分在gcc中也不起作用。这毫无意义。它应该是虚拟void foo();
,并且只使用一次。您希望如何使用A
、B
和C
?有许多可能性:,…(这些可能定义了比需要更多的函数)[dcl.意思]/1禁止在(成员)函数的声明中使用限定id:“当声明器id是限定的时,声明应引用限定符所引用的类或命名空间的先前声明的成员[…]”,因此任何virtual void X::foo();
都是非法的(作为C
中的声明)事实上,在我之前的评论中链接的代码是误导性的,因为C::A::foo
实际上意味着A::foo
(谢谢@DyP)。这里有一些更简单的例子:和。只是一句话:定义void C::A::foo(){}
和void C::B::foo(){}
分别为纯虚拟函数A::foo
和B::foo
提供定义(并且不是必需的){cout@dyp只是好奇为什么使用语法void C::A::foo(){}
为A::foo()提供定义是合法的
,使用这种语法而不是重写A::for(){}有什么好处吗
直接?我看起来很困惑,如果A
是一个内部类怎么办?我编译了这段代码,很惊讶它是合法的。@Dreamer这是一般概念的结果。定义成员函数时,您只需使用其中一种方法引用成员的名称;当您想要c时,也可以使用相同的引用方法所有函数,例如this->C::A::foo();
名称A
是C
的成员,因为类A
隐式定义了一个名为A
的成员,该成员引用自身(注入类名称)由于继承,这个成员A::A
在C
中是可见的。如果CA::foo
和CB::foo
都需要访问对象内的共享数据,那么您可能需要第三个基类来包含共享部分,然后您就得到了可怕的菱形继承。真是一团糟!请注意,abiguity可以解释为城市解析:c.A::foo()
如果我把virtual
放在所有foo
方法之前或者只放一次,有什么区别?如果我把virtual放在方法A::foo或B::foo或CA::foo等中有关系吗?或者它是不相关的?@CătălinaSîrbu如果你显式地写virtual
或者它有相同的签名,那么函数是虚拟的(名称、参数)作为任何基类中的虚拟函数。因此,此处的大多数virtual
关键字都是多余的。我将virtual
预先添加到所有虚拟函数(即使没有必要)以直接显示该函数是虚拟的。
class A
{
public:
struct tag_a { };
virtual void foo(tag_a) = 0;
};
class B
{
public:
struct tag_b { };
virtual void foo(tag_b) = 0;
};
class C : public A, public B
{
void foo(tag_a) override;
void foo(tag_b) override;
};