if(param1>param2) return cst;
,编译器在某些情况下可以将整个函数调用减少为常数)。 - curiousguy虚拟方法被用于接口设计中。例如,在Windows中有一个名为IUnknown的接口,如下所示:
interface IUnknown {
virtual HRESULT QueryInterface (REFIID riid, void **ppvObject) = 0;
virtual ULONG AddRef () = 0;
virtual ULONG Release () = 0;
};
这些方法需要接口用户自行实现。它们对于创建和销毁某些必须继承IUnknown的对象至关重要。在这种情况下,运行时环境知道这三个方法,并期望在调用它们时将它们实现。因此,在某种意义上,它们充当对象本身和使用该对象的任何内容之间的合同。
IUnknown
的实例,因此所有子类必须实现所有这些方法才能编译。没有不实现它们然后在运行时发现的危险(但显然可以错误地实现它们!)。今天我学到了Windows使用单词“interface”作为宏定义,可能是因为他们的用户不能(A)看到名称中的前缀“I”,或者(B)查看类以查看它是一个接口。唉 - underscore_d#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
#ifdef VIRTUAL
virtual string says() { return "??"; }
#else
string says() { return "??"; }
#endif
};
class Dog: public Animal
{
public:
string says() { return "woof"; }
};
string func(Animal *a)
{
return a->says();
}
int main()
{
Animal *a = new Animal();
Dog *d = new Dog();
Animal *ad = d;
cout << "Animal a says\t\t" << a->says() << endl;
cout << "Dog d says\t\t" << d->says() << endl;
cout << "Animal dog ad says\t" << ad->says() << endl;
cout << "func(a) :\t\t" << func(a) << endl;
cout << "func(d) :\t\t" << func(d) << endl;
cout << "func(ad):\t\t" << func(ad)<< endl;
}
两个不同的结果是:
没有 #define virtual,它在编译时绑定。Animal *ad 和 func(Animal *) 都指向 Animal 的 says() 方法。
$ g++ virtual.cpp -o virtual
$ ./virtual
Animal a says ??
Dog d says woof
Animal dog ad says ??
func(a) : ??
func(d) : ??
func(ad): ??
$ g++ virtual.cpp -D VIRTUAL -o virtual
$ ./virtual
Animal a says ??
Dog d says woof
Animal dog ad says woof
func(a) : ??
func(d) : woof
func(ad): woof
class Animal:
def says(self):
return "??"
class Dog(Animal):
def says(self):
return "woof"
def func(a):
return a.says()
if __name__ == "__main__":
a = Animal()
d = Dog()
ad = d # dynamic typing by assignment
print("Animal a says\t\t{}".format(a.says()))
print("Dog d says\t\t{}".format(d.says()))
print("Animal dog ad says\t{}".format(ad.says()))
print("func(a) :\t\t{}".format(func(a)))
print("func(d) :\t\t{}".format(func(d)))
print("func(ad):\t\t{}".format(func(ad)))
输出结果为:
Animal a says ??
Dog d says woof
Animal dog ad says woof
func(a) : ??
func(d) : woof
func(ad): woof
这与C++的虚拟定义相同。请注意,d和ad是两个不同的指针变量,引用/指向同一个Dog实例。表达式(ad is d)返回True,它们的值相同<main.Dog object at 0xb79f72cc>。
就我对这个问题的理解,它问的是为什么C++需要一个虚拟关键字。
因为编译器可能无法在编译阶段确定要调用哪个实例的方法。
以下代码提供了一个示例:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void Say() { cout << "Im animal"; }
};
class Cat : public Animal {
public:
void Say() { cout << "Im cat"; }
};
class Dog : public Animal {
public:
void Say() { cout << "Im dog"; }
};
Animal* NewAnimal() {
int v = 1;
// The input is totally unpredictable.
cin >> v;
switch (v) {
case 1:
return new Cat();
case 2:
return new Dog();
default:
return new Animal();
}
}
int main(void) {
auto x = NewAnimal();
// Compiler can't determine what x is (a dog or a cat, or some animal else)
// in compiling stage. So, to call which Say function, is runtime related.
// That's to say, the Say function requires dynamically binding.
// What the keyword virtual does, is to tell the compiler the Say function
// should be determined at runtime stage, but not compiling stage.
x->Say();
return 0;
}
哪种动物的叫声是完全不可预测的。 我们必须在运行时动态决定使用哪一个。
归根结底,虚函数使生活更轻松。让我们借鉴M Perry的一些想法,并描述如果没有虚函数而只能使用成员函数指针会发生什么。在没有虚函数的正常估计中,我们有:
class base {
public:
void helloWorld() { std::cout << "Hello World!"; }
};
class derived: public base {
public:
void helloWorld() { std::cout << "Greetings World!"; }
};
int main () {
base hwOne;
derived hwTwo = new derived();
base->helloWorld(); //prints "Hello World!"
derived->helloWorld(); //prints "Hello World!"
好的,那就是我们知道的。现在让我们尝试使用成员函数指针来实现:
#include <iostream>
using namespace std;
class base {
public:
void helloWorld() { std::cout << "Hello World!"; }
};
class derived : public base {
public:
void displayHWDerived(void(derived::*hwbase)()) { (this->*hwbase)(); }
void(derived::*hwBase)();
void helloWorld() { std::cout << "Greetings World!"; }
};
int main()
{
base* b = new base(); //Create base object
b->helloWorld(); // Hello World!
void(derived::*hwBase)() = &derived::helloWorld; //create derived member
function pointer to base function
derived* d = new derived(); //Create derived object.
d->displayHWDerived(hwBase); //Greetings World!
char ch;
cin >> ch;
}
虽然我们可以使用成员函数指针来完成一些任务,但它们并不像虚函数那样灵活。在类中使用成员函数指针是有技巧的;至少在我的实践中,几乎总是必须在主函数或从成员函数内部调用成员函数指针,就像上面的例子一样。
另一方面,虚函数虽然可能会带来一些函数指针的开销,但却极大地简化了事情。
编辑:还有一种类似的方法,由eddietree提供:c++虚函数与成员函数指针(性能比较)。
继续@user6359267的回答,C++的作用域层次结构是
global -> namespace -> class -> local -> statement
#include <iostream>
#include <string>
class Parent
{
public:
std::string GetName() { return "Parent"; }
};
class Child : public Parent
{
public:
std:::string GetName() { return "Child"; }
};
int main()
{
Parent* parent = new Parent();
std::cout << parent->GetName() << std::endl;
Child* child = new Child();
std::cout << child->GetName() << std::endl;
*parent = child;
std::cout << child->GetName() << std::endl;
return 0;
}
输出
Parent
Child
Parent