如果你有这样的事情:
#include <iostream>
template<typename T> class A
{
public:
void func()
{
T::func();
}
};
class B : public A<B>
{
public:
virtual void func()
{
std::cout << "into func";
}
};
class C : public B
{
};
int main()
{
C c;
c.func();
return 0;
}
是否动态调度func()? 你怎么能实现A类,如果B有一个虚拟覆盖,它是动态调度的,但如果B没有,则静态调度?
编辑:我的代码没编译?对不起大家。我现在病得很厉害。我的新代码也没有编译,但这是问题的一部分。此外,这个问题适合我,而不是常见问题。
#include <iostream>
template<typename T> class A
{
public:
void func()
{
T::func();
}
};
class B : public A<B>
{
public:
virtual void func()
{
std::cout << "in B::func()\n";
}
};
class C : public B
{
public:
virtual void func() {
std::cout << "in C::func()\n";
}
};
class D : public A<D> {
void func() {
std::cout << "in D::func()\n";
}
};
class E : public D {
void func() {
std::cout << "in E::func()\n";
}
};
int main()
{
C c;
c.func();
A<B>& ref = c;
ref.func(); // Invokes dynamic lookup, as B declared itself virtual
A<D>* ptr = new E;
ptr->func(); // Calls D::func statically as D did not declare itself virtual
std::cin.get();
return 0;
}
visual studio 2010\projects\temp\temp\main.cpp(8): error C2352: 'B::func' : illegal call of non-static member function
visual studio 2010\projects\temp\temp\main.cpp(15) : see declaration of 'B::func'
visual studio 2010\projects\temp\temp\main.cpp(7) : while compiling class template member function 'void A<T>::func(void)'
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(13) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
答案 0 :(得分:2)
我不确定我明白你在问什么,但看起来你错过了必不可少的CRTP演员:
template<class T>
struct A {
void func() {
T& self = *static_cast<T*>(this); // CRTP cast
self.func();
}
};
struct V : A<V> { // B for the case of virtual func
virtual void func() {
std::cout << "V::func\n";
}
};
struct NV : A<NV> { // B for the case of non-virtual func
void func() {
std::cout << "NV::func\n";
}
};
如果T没有声明自己的func,这将是无限递归,因为self.func将找到A&lt; T&gt; :: func。即使派生的T类(例如下面的DV)声明它自己的func但T没有声明它也是如此。
使用不同的最终覆盖物进行测试,以显示宣传的调度工作:
struct DV : V {
virtual void func() {
std::cout << "DV::func\n";
}
};
struct DNV : NV {
void func() {
std::cout << "DNV::func\n";
}
};
template<class B>
void call(A<B>& a) {
a.func(); // always calls A<T>::func
}
int main() {
DV dv;
call(dv); // uses virtual dispatch, finds DV::func
DNV dnv;
call(dnv); // no virtual dispatch, finds NV::func
return 0;
}
答案 1 :(得分:1)
有点矛盾,不是吗? A类用户可能对B或C一无所知。如果您有A的引用,了解如何实现A类,如果B有虚拟覆盖,则动态调度,但如果B没有,则静态调度?
func()
是否需要动态调度的唯一方法是查阅vtable。由于A::func()
不是虚拟的,因此没有条目,因此无处放置信息。一旦你虚拟化,你就会查看vtable并进行动态调度。
获取直接函数调用(或内联)的唯一方法是使用非虚函数,而不是通过基类指针间接传递。
编辑:我认为Scala中的这个成语是class C: public B, public A<C>
(用子类重复特征)但这在C ++中不起作用,因为它使A<T>
的成员在C
中不明确{1}}。
答案 2 :(得分:1)
在您的特定示例中,不需要动态分派,因为c
的类型在编译时是已知的。对B::func
的调用将被硬编码。
如果您通过func
呼叫B*
,那么您将调用虚拟功能。但是在你非常人为的例子中,那将再次让你B::func
。
从A*
谈论动态调度没有多大意义,因为A
是模板类 - 你不能制作通用的A
,只有一个是绑定到特定的子类。
答案 3 :(得分:1)
如何实现A类,如果B有虚拟覆盖,则动态调度,但如果B没有,则静态调度?
正如其他人所注意到的那样,很难理解这个问题,但它让我记住了很久以前我学到的东西,所以这里有很长的回答你的问题:
template<typename Base> class A : private Base
{
public:
void func()
{
std::count << "A::func";
}
};
鉴于此,它取决于A
的基础func()
是否为虚拟。如果Base
声明virtual
,那么它也会在A
中变为虚拟。否则它不会。见:
class V
{
public:
virtual void func() {}
};
class NV
{
};
class B : public A<V> // makes func() virtual
{
public:
void func()
{
std::count << "B::func";
}
};
class C : public A<NV> // makes func() non-virtual
{
public:
void func()
{
std::count << "C::func";
}
};
这会碰巧回答你的问题吗?
答案 4 :(得分:0)
是否动态调度函数取决于两件事:
a)对象表达式是引用还是指针类型
b)函数(重载决议解析为)是否为虚拟。
现在来到你的代码:
C c;
c.func(); // object expression is not of pointer/reference type.
// So static binding
A <B> & ref = c;
ref.func(); // object expression is of reference type, but func is
// not virtual. So static binding
A<D>* ptr = new D;
ptr->func(); // object expression is of pointer type, but func is not
// virtual. So static binding
简而言之,'func'不会动态调度。
注意::抑制虚函数调用机制。
$ 10.3 / 12-“明确资格 范围运算符(5.1)抑制 虚拟的“呼叫机制。
OP2中的代码给出错误,因为只有当'Y'是'X'范围内的静态成员时,语法X :: Y才能用于在'X'范围内调用'Y'。
答案 5 :(得分:-1)
似乎你只需添加一些痕迹和用法来回答你自己的问题......
#include <iostream>
template<typename T> struct A {
void func() {
T::func();
}
};
struct B1 : A<B1> {
virtual void func() {
std::cout << "virtual void B1::func();\n";
}
};
struct B2 : A<B2> {
void func() {
std::cout << "void B2::func();\n";
}
};
struct C1 : B1 { };
struct C2 : B2 { };
struct C1a : B1 {
virtual void func() {
std::cout << "virtual void C1a::func();\n";
}
};
struct C2a : B2 {
virtual void func() {
std::cout << "virtual void C2a::func();\n";
}
};
int main()
{
C1 c1;
c1.func();
C2 c2;
c2.func();
B1* p_B1 = new C1a;
p_B1->func();
B2* p_B2 = new C2a;
p_B2->func();
}
输出:
virtual void B1::func();
void B2::func();
virtual void C1a::func();
void B2::func();
结论:A确实具有B的功能的虚拟性。