我对C ++虚函数有疑问。
派生类(DerivedAlgo
)实现虚函数(BaseAlgo::process
),但通过使用DerivedData
类型作为输入参数而不是BaseData,在函数签名中稍微改变一点。
尽管基类中有纯抽象函数,但我仍然能够创建DerivedAlgo
类的实例,并且编译器根本不会抱怨。
我只是想知道任何人都知道可以解释以下代码的任何C ++规则。
class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
virtual void process(DerivedData& data){
std::cout << "hello world!" << std::endl;
}
};
在我的另一个示例代码中,我定义了process(DerivedData&)
和process(BaseData&)
。
编译器仍然可以在不抱怨任何歧义的情况下运行。
class DerivedAlgo{
public:
virtual void process(DerivedData& data){...}
virtual void process(BaseData& data){...}
};
BaseData baseData;
DerivedData derivedData;
derivedAlgo.process(baseData);
derivedAlgo.process(derivedData);
我非常感谢你的任何投入。谢谢!
答案 0 :(得分:1)
你的第一个例子不能在g ++ 4.2上编译。作为参考,我这样做了:
#include <iostream>
class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
virtual void process(DerivedData& data){
std::cout << "hello world!" << std::endl;
}
};
int main()
{
DerivedAlgo da;
return 0;
}
得到了这个:
error: cannot declare variable 'da' to be of abstract type 'DerivedAlgo'
note: because the following virtual functions are pure within 'DerivedAlgo'
note: virtual void BaseAlgo::process(BaseData&)
如果我的示例做了编译,那么你几乎肯定会有一个错误的编译器。
您的第二个示例将编译,因为它会覆盖抽象函数。第一个调用将调用基本数据版本,而第二个调用将调用派生的派生版本。
请注意,在您的第一个示例中,您隐藏函数的process(base)
版本,而不是覆盖它。覆盖虚函数时,不应更改函数签名。
答案 1 :(得分:1)
您确定没有收到编译错误吗?
当我编译它时(在MSVC9中):
#include <cstdlib>
#include <memory>
#include <iostream>
class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
virtual void process(DerivedData& data){
data;
std::cout << "hello world!" << std::endl;
}
};
int main()
{
DerivedAlgo da;
}
我收到了预期的错误:
1>.\main.cpp(21) : error C2259: 'DerivedAlgo' : cannot instantiate abstract class
1> due to following members:
1> 'void BaseAlgo::process(BaseData &)' : is abstract
1> .\main.cpp(9) : see declaration of 'BaseAlgo::process'
这是因为您无法使用不同的参数列表覆盖虚拟:
2 /如果虚拟成员函数vf是 在类Base和a中声明 class派生,直接派生或 成员之间的间接来自Base 函数vf具有相同的名称和 与Base :: vf相同的参数列表是 声明,然后Derived :: vf也是 虚拟的(无论是否如此 宣布)并覆盖97) 基:: VF。
在派生类中声明覆盖的唯一余地是使用协变返回类型。
如果您从未真正调用派生类,那么您的编译器可能无法彻底检查您的代码。
答案 2 :(得分:0)
你遇到的问题是c ++不支持double dispatch。您需要在BaseAlgo类上使用Visitor pattern。