请查看示例1和示例2。
示例1与示例2的不同之处仅在于**类IA **的重写方法run()
问题写在最后。
示例1:
#include <iostream>
class IA {
public:
void run() {
print();
}
void print() {
std::cout << "IA::print() \n";
}
};
class A : public IA {
public:
void print() {
std::cout << "A:: \n";
}
};
int main() {
A a1;
a1.run();
A * ptr = new A;
ptr->run();
}
此代码显示:
IA :: print()
IA :: print()
示例2:
#include <iostream>
class IA {
public:
void run() {
print();
}
void print() {
std::cout << "IA::print() \n";
}
};
class A : public IA {
public:
void run() {
print();
}
void print() {
std::cout << "A:: \n";
}
};
int main() {
A a1;
a1.run();
A * ptr = new A;
ptr->run();
}
此代码显示:
A ::
答::
为什么这样打印?有什么区别?
谢谢。
答案 0 :(得分:3)
您选择不对print
进行虚拟化。这意味着不会发生动态调度。在调用该方法的任何时候,都会使用本地类型信息来确定要调用的方法。
void run() {
print();
}
因此,当您调用非虚拟print
时,将调用从写入print
的地方看到的任何本地run
函数。
在IA::run
中,唯一可见的print
是IA::print
。因此IA::run
呼叫IA::print
。
在A::run
中,您可以同时看到IA::print
和A::print
;但是第二个隐藏了第一个。因此称为A::print
。
对象的实际动态类型是什么都没有关系,因为您没有要求进行虚拟调度。您要求使用本地静态类型信息选择该函数。
您可以要求虚拟派遣:
class IA {
public:
void run() {
print();
}
virtual void print() {
std::cout << "IA::print() \n";
}
};
我将关键字virtual
添加到了print
。现在,第一个版本将称为A::
的{{1}}版本。
某些语言使所有方法隐式虚拟。 C ++不会,因为虚拟方法会产生一些运行时开销,并且C ++会尝试不让您为未使用的东西付费。
答案 1 :(得分:0)
在第一个程序中,成员函数run是基类的函数。在函数中,指针this
的静态类型为IA
。根据{{1}}的静态类型在IA类中搜索功能打印。
在第二个程序中,类A具有运行和打印这两个功能。它们隐藏了IA类的相应功能。因此它们被称为
从C ++标准(13.2成员名称查找)
1成员名称查找确定名称的含义(id表达式) 在类范围内(6.3.7)。名称查询可能会导致模棱两可 在这种情况下,程序格式不正确。 对于id表达式,名称 查找从此类的范围开始; 为合格ID,名称 查找从嵌套名称说明符的范围开始。名称查询 发生在访问控制之前(6.4,第14条)。