为什么我可以从派生类调用基模板类方法
Why can I call base template class method from derived class
我决定测试"有效C++"中的一个示例,但我没有得到我预期的结果。所以,显然这个(简化的(代码不应该编译:
template <class T>
struct A {
void f(){}
};
template <class T>
struct B : public A <T> {
void f2() { f(); } // calling base function - will not compile
};
以下是解释(为简单起见,类名已更改(:
上面的代码不会编译,至少不能使用符合标准的编译器。这样的编译器会抱怨
f
不存在。我们可以看到f
在基类中,但编译器不会在那里查找它。我们需要了解原因。 问题是当编译器遇到类模板的定义
B
时,它们 不知道它继承自哪个类。当然,这是A<T>
,但T
是一个模板参数, 一个直到以后(当B
被实例化时(才会知道的。不知道T
什么 是,没有办法知道A<T>
类是什么样子的。特别是,没有办法知道它是否具有f
功能。
我的编译器(Visual Studio(不介意...它甚至不显示任何警告。
上面的代码是否正确?
template <class T>
struct A {
void f(){}
};
template <class T>
struct B : public A <T> {
void f2() { f(); } // calling base function - will not compile
};
在派生模板中,表达式f()
不依赖于任何模板参数,因此编译器会在第一阶段查找期间尝试解析它。此时,模板尚未使用该类型实例化,编译器不会查看基A<T>
。原因是编译器不可能知道对于实例化的类型,是否存在可能不包含任何成员的A<T>
专用化。
解决方案是使表达式依赖,最简单的方法是用this->
限定:
template <typename T>
void B<T>::f2() { this->f(); }
由于表达式现在依赖于表达式,因此查找将延迟到第二阶段,在该阶段中,类型被替换,A<T>
是具体类型。另一种选择是使用定义它的类进行限定:
template <typename T>
void B<T>::f2() { A<T>::f(); }
表达式再次变得依赖,并将在第二阶段进行解析。主要区别在于,在第二种情况下,调用是限定的,因此不使用动态调度。如果A<T>::f()
是虚拟的,它仍然会执行A<T>::f()
,而不是最终的覆盖者。
代码正确吗?哈哈VS接受吗?是的。
这是 Visual Studio 编译器中的已知不符合项,它不实现两阶段查找。它将模板内的所有查找延迟到第二阶段,此时查找成功。
- 使用用户定义的参数调用future/async并调用类方法
- 重载类方法的不明确调用
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 从基类实例调用派生类方法而不进行强制转换
- 派生类调用父类的方法,该方法调用重写的虚拟方法调用错误的方法
- 函数从唯一代码调用正确的子类方法
- C++ |DLL / EXE - 如何从导出的类调用另一个类方法?
- C++:从属性类调用顶级类方法
- 指向类方法调用的指针
- 有没有办法从同一类中的函子调用类方法?
- 有没有办法禁止派生类中的基类方法调用?
- 从类方法调用命名空间中名为 Same 的函数时,重载解析失败
- 我可以从析构函数的类方法调用它吗
- C++指向类方法调用的指针
- 基类方法调用派生类方法,任何可能的解决方案
- 从基类方法调用虚拟方法
- 非常具体的子类方法调用
- 类方法调用是否会在for循环中进行优化
- 使用具有相同声明的类方法调用全局函数
- 如何在c++中实现抽象类,同时允许子类方法调用