派生类在此代码中的作用如下:
class Base
{
public:
virtual std::string Name(){ return "Base Class"}
};
class Derived : public Base
{
public:
std::string Name() {return "Derived Class"}
}
int main()
{
Base* object = new Derived();
return 0;
}
我在学习教程,但不明白基类实例化中的派生类在上面的代码中做了什么。
我们的目标是实现多态性,这是一个OOP概念,它允许您使用派生类方法重写基类。
请考虑以下事项:
class Base {
public:
//virtual keyword allows method to be overriden
virtual std::string Name() { return "Base Class"; }
//virtual destructor needed for polymorphism otherwise it can lead to undefined behavior
virtual ~Base(){}
};
class Derived : public Base {
public:
//optional keyword override signal the method has been overriden
std::string Name() override { return "Derived Class"; }
};
class Derived2 : public Base {
public:
std::string Name() override { return "Derived Class 2"; }
};
int main() {
Base *object = new Derived();
Base *object2 = new Derived2();
Base *object3 = new Base();
//collection of objects of type Base* which can hold any class of the family
Base *collection[] = {object, object2, object3};
for (auto &obj : collection) {//test print
std::cout << obj->Name() << std::endl;
}
}
正如注释所解释的,我可以有一个相同家族的不同对象的集合,当您调用name()
时,方法调用将依赖于该对象。
输出:
Derived Class
Derived Class 2
Base Class
将main
修改为:
int main()
{
Base* object = new Derived();
std::cout << object->Name() << std::endl;
return 0;
}
并添加3个缺失的“;” 在您的代码中,您将看到编写派生类,调用的方法名是派生对象的真正类型。
注意,虽然Name在基础上是虚拟的,但它也是派生的,即使你没有明确地说。
virtual
允许在应用方法时使用对象的真实类型,因此即使对象也被声明为Base当Name为virtual时调用的版本是派生的真实类型之一
但是,如果删除编写基类的基中名称的定义中的virtual
,因为对象被声明为基,那么被调用的方法就是在基上定义的名称。
结果将是相同的,在派生对象上添加virtual
,但仍然在基上删除它,因为对于被声明为基的编译器对象,并且名称在基上不是虚拟的,调用时不考虑对象的实际类型
因此,具有:
#include <iostream>
#include <string>
class Base
{
public:
virtual std::string virtualName(){ return "Base Class";}
std::string nonVirtualName(){ return "Base Class";}
};
class Derived : public Base
{
public:
std::string virtualName() {return "Derived Class";} // implicitely virtual
std::string nonVirtualName(){ return "Base Class";}
};
int main()
{
Base* object = new Derived();
std::cout << object->virtualName() << std::endl;
std::cout << object->nonVirtualName() << std::endl;
return 0;
}
编译和执行:
bruno@bruno-XPS-8300:/tmp$ g++ -Wall a.cc
bruno@bruno-XPS-8300:/tmp$ ./a.out
Derived Class
Base Class
bruno@bruno-XPS-8300:/tmp$
注意,如果您在main
的末尾添加delete object;
,并且由于默认析构函数不是虚拟的,那么调用的析构函数正是nonVirtualName的Base析构函数,而不对derived进行任何操作。 在基上定义析构函数为虚拟是正确的做法,这意味着析构函数至少在派生上隐式为虚拟,从而允许在delete object;
上执行两个析构函数