正常情况下,我们在类继承中,如果使用相同的成员函数,结果输出按照下面的代码执行也是正确的
class Entry
{
public:
std::string GetName() { return "Entry"; }
};
class Player : public Entry
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}
std::string GetName() { return m_Name; }
};
int main()
{
Entry* e = new Entry();
std::cout << e->GetName() << std::endl;
Player* p = new Player("David");
std::cout << p->GetName() << std::endl;
std::cin.get();
}
输出结果是
Entry
David
修改部分代码,再次运行,没有得到我们预期的结果,具体如下
int main()
{
Entry* e = new Entry();
std::cout << e->GetName() << std::endl;
Player* p = new Player("David");
std::cout << p->GetName() << std::endl;
Entry* entry = new Player("David");
// 这里输出的结果并不是我们预期的,而是"Entry"
std::cout << Entry->GetName() << std::endl;
std::cin.get();
}
执行后输出的结果为:
Entry
David
Entry
如果我们编写一个通用的输出函数,结果就不对了,下面是在上例增加的代码
void print(Entry* entry)
{
std::cout << entry->GetName() << std::endl;
}
int main()
{
Entry* e = new Entry();
print(e);
Player* p = new Player("David");
print(p);
std::cin.get();
}
执行输出的结果为:
Entry
Entry
通过虚函数virtual
,我们就可以成功的覆盖,显示预期的结果,具体修改如下
class Entry
{
public:
// 虚函数
virtual std::string GetName() { return "Entry"; }
};
// .....
void print(Entry* entry)
{
std::cout << entry->GetName() << std::endl;
}
int main()
{
Entry* e = new Entry();
print(e);
Player* p = new Player("David");
print(p);
std::cin.get();
}
输出结果就是正确的:
Entry
David
为了更好得提现类继承,方法的覆盖,我们采用关键字override
来修饰,代码可读性更好,同时还可以检查覆盖的方法是否和基类一致,完整代码
#include <iostream>
class Entry
{
public:
virtual std::string GetName() { return "Entry"; }
};
class Player : public Entry
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}
// 覆盖(重写)基类的方法
std::string GetName() override { return m_Name; }
};
void Print(Entry* entry)
{
std::cout << entry->GetName() << std::endl;
}
int main()
{
Entry* e = new Entry();
Print(e);
Player* p = new Player("David");
Print(p);
std::cin.get();
}
代码可以正确的输出
Entry
David
虚函数本质是在编译器中建立一个虚拟表,根据基础类与基类的关系,这样编译器会根据执行的实例调用不同的方法,这里虽然有性能上的损耗,但是可以忽略不考虑
如果我们将基类的函数为纯虚函数,那就意味着,我们需要继承给基类的派生类去实现这个方法,纯函数的定义如下
class Entry
{
public:
// 纯虚函数的定义,直接让函数等于 0
virtual std::string GetName() = 0;
};
// ……
int main()
{
Entry* e = new Entry();
// 这里调用纯虚函数的GetName() 方面就会报错
Print(e);
Player* p = new Player("David");
Print(p);
std::cin.get();
}
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): error C2259: “Entry”: 无法实例化抽象类
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(5,8): message : 参见“Entry”的声明
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): message : 由于下列成员:
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(30,23): message : “std::string Entry::GetName(void)”: 是抽象的
1>C:\Users\yangy\source\repos\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(8,22): message : 参见“Entry::GetName”的声明
基类中定义的纯虚函数,是要求派送类中必须要实现的
// 对于多重继承的虚函数,我们为单独设置一个打印虚拟类,这样就不需要考虑具体是什么类了,完整的代码
#include <iostream>
class Printable
{
public:
virtual std::string GetClassName() = 0;
};
class Entry: public Printable
{
public:
virtual std::string GetName() { return "Entry"; };
std::string GetClassName() override { return "Entry"; }
};
class Player : public Entry
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}
// 覆盖(重写)基类的方法
std::string GetName() override { return m_Name; }
std::string GetClassName() override { return "Player"; }
};
void Print(Printable* entry)
{
std::cout << entry->GetClassName() << std::endl;
}
int main()
{
Entry * e = new Entry();
Entry * p = new Player("David");
Print(e);
Print(p);
std::cin.get();
}
运行输出结果
Entry
David
网友评论