C/C++编程笔记:高级C++知识 | 虚拟构造器

215 阅读4分钟

我们可以在C ++中使类构造函数_虚拟化_以创建多态对象吗?不会。C++是静态类型的(RTTI的目的有所不同)语言,对于C ++编译器来说,多态创建对象是没有意义的。编译器必须知道创建对象的类类型。换句话说,从C ++编译器的角度来看,要创建哪种类型的对象是编译时的决定。如果我们将构造函数设为虚拟,则编译器会标记错误。实际上,除了_inline_之外,构造函数的声明中不允许其他关键字。

在实际情况下,我们需要基于一些输入在类层次结构中创建派生类对象。换句话说,对象创建和对象类型紧密耦合,这迫使修改扩展。虚拟构造器的目的是使对象创建与类型脱钩

我们如何在运行时创建所需的对象类型?例如,请参见下面的示例程序。

#include <iostream>using namespace std;//// LIBRARY STARTclass Base{public:Base() { }virtual // Ensures to invoke actual object destructor~Base() { }// An interfacevirtual void DisplayAction() = 0;};class Derived1 : public Base{public:Derived1(){cout << "Derived1 created" << endl;}~Derived1(){cout << "Derived1 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived1" << endl;}};class Derived2 : public Base{public:Derived2(){cout << "Derived2 created" << endl;}~Derived2(){cout << "Derived2 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived2" << endl;}};//// LIBRARY ENDclass User{public:// Creates Drived1User() : pBase(nullptr){// What if Derived2 is required? - Add an if-else ladder (see next sample)pBase = new Derived1();}~User(){if( pBase ){delete pBase;pBase = nullptr;}}// Delegates to actual objectvoid Action(){pBase->DisplayAction();}private:Base *pBase;};int main(){User *user = new User();// Need Derived1 functionality onlyuser->Action();delete user;}

在以上示例中,假定层次结构_Base_,_Derived1_和_Derived2_是库代码的一部分。_User_类是试图利用层次结构的实用程序类。的_主要_功能是消耗_基地_经由层级的功能 的用户 类。

该_用户_类构造函数创建_Derived1_对象,始终。如果_用户_的使用者(在我们的例子中是_主要__用户_)需要_Derived2_功能,则_用户_需要创建“ new Derived2() ”并强制重新编译。重新编译是不好的设计方法,因此我们可以选择以下方法。

在详细介绍之前,让我们回答一下,谁将指示创建_Derived1_或_Derived2_对象?显然,它是_User_类的_使用者_。该_用户_类可以使用的if-else梯的创建或者_Derived1_或_Derived2的_,如下面的示例所示:

#include <iostream>using namespace std;//// LIBRARY STARTclass Base{public:Base() { }virtual // Ensures to invoke actual object destructor~Base() { }// An interfacevirtual void DisplayAction() = 0;};class Derived1 : public Base{public:Derived1(){cout << "Derived1 created" << endl;}~Derived1(){cout << "Derived1 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived1" << endl;}};class Derived2 : public Base{public:Derived2(){cout << "Derived2 created" << endl;}~Derived2(){cout << "Derived2 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived2" << endl;}};//// LIBRARY ENDclass User{public:// Creates Derived1 or Derived2 based on inputUser() : pBase(nullptr){int input; // ID to distinguish between// Derived1 and Derived2cout << "Enter ID (1 or 2): ";cin >> input;while( (input != 1) && (input != 2) ){cout << "Enter ID (1 or 2 only): ";cin >> input;}if( input == 1 ){pBase = new Derived1;}else{pBase = new Derived2;}// What if Derived3 being added to the class hierarchy?}~User(){if( pBase ){delete pBase;pBase = nullptr;}}// Delegates to actual objectvoid Action(){pBase->DisplayAction();}private:Base *pBase;};int main(){User *user = new User();// Need either Derived1 or Derived2 functionalityuser->Action();delete user;}

上面的代码*不*开放扩展,这是一种不灵活的设计。简而言之,如果库使用新类_Derived3_更新_基_类层次结构。_User_类如何创建_Derived3_对象?一种方法是更新基于新输入ID 3来创建_Derived3_对象的if-else阶梯,如下所示,

#include <iostream>using namespace std;class User{public:User() : pBase(nullptr){// Creates Drived1 or Derived2 based on needint input; // ID to distinguish between// Derived1 and Derived2cout << "Enter ID (1 or 2): ";cin >> input;while( (input != 1) && (input != 2) ){cout << "Enter ID (1 or 2 only): ";cin >> input;}if( input == 1 ){pBase = new Derived1;}else if( input == 2 ){pBase = new Derived2;}else{pBase = new Derived3;}}~User(){if( pBase ){delete pBase;pBase = nullptr;}}// Delegates to actual objectvoid Action(){pBase->DisplayAction();}private:Base *pBase;};

上面的修改迫使_User_类的_用户_重新编译,不好的(不灵活的)设计!并且不会因_基础_扩展而关闭_用户_类的进一步修改。

问题在于对象的创建。将新类添加到层次结构中,从而强制重新编译_User_类的依赖项。我们不能将创建对象的操作委托给类层次结构本身或虚拟行为的函数吗?通过将对象创建委托给类层次结构(或静态函数),我们可以避免_User_和_Base_层次结构之间的紧密耦合。理论足够,请参见以下代码,

#include <iostream>using namespace std;//// LIBRARY STARTclass Base{public:// The "Virtual Constructor"static Base *Create(int id);Base() { }virtual // Ensures to invoke actual object destructor~Base() { }// An interfacevirtual void DisplayAction() = 0;};class Derived1 : public Base{public:Derived1(){cout << "Derived1 created" << endl;}~Derived1(){cout << "Derived1 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived1" << endl;}};class Derived2 : public Base{public:Derived2(){cout << "Derived2 created" << endl;}~Derived2(){cout << "Derived2 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived2" << endl;}};class Derived3 : public Base{public:Derived3(){cout << "Derived3 created" << endl;}~Derived3(){cout << "Derived3 destroyed" << endl;}void DisplayAction(){cout << "Action from Derived3" << endl;}};// We can also declare "Create" outside Base// But it is more relevant to limit it's scope to BaseBase *Base::Create(int id){// Just expand the if-else ladder, if new Derived class is created// User code need not be recompiled to create newly added class objectsif( id == 1 ){return new Derived1;}else if( id == 2 ){return new Derived2;}else{return new Derived3;}}//// LIBRARY END//// UTILITY STARTclass User{public:User() : pBase(nullptr){// Receives an object of Base hierarchy at runtimeint input;cout << "Enter ID (1, 2 or 3): ";cin >> input;while( (input != 1) && (input != 2) && (input != 3) ){cout << "Enter ID (1, 2 or 3 only): ";cin >> input;}// Get object from the "Virtual Constructor"pBase = Base::Create(input);}~User(){if( pBase ){delete pBase;pBase = nullptr;}}// Delegates to actual objectvoid Action(){pBase->DisplayAction();}private:Base *pBase;};//// UTILITY END//// Consumer of User (UTILITY) classint main(){User *user = new User();// Action required on any of Derived objectsuser->Action();delete user;}

该_用户_类是独立的对象创建的。它将责任委托给_Base_,并以ID的形式提供输入。如果库添加了新的类_Derived4_,则库修改器将扩展_Create_内的if-else梯形图以返回正确的对象。消费者_用户_不需要重新编译他们的代码由于延长_基地_。

请注意,函数_Create_用于在运行时返回不同类型的_基_类对象。它的作用类似于虚拟构造函数,在模式术语中也称为_Factory Method_。

模式世界展示了实现上述概念的不同方法。

以上就是今天的全部内容了。每日分享小知识,希望对你有帮助~

**另外如果你想更好的提升你的编程能力,学好C语言C++编程!**弯道超车,快人一步!笔者这里或许可以帮到你~

C语言C++编程学习交流圈子,**QQ群【951258402】**微信公众号:C语言编程学习基地

分享(源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

编程学习视频分享: