高级C++虚拟构造函数

我们能做一个类构造函数吗 事实上的 在C++中创建多态对象?C++是静态类型的(RTTI的目的是不同的)语言,对于C++编译器来说,多态地创建一个对象是没有意义的。编译器必须知道创建对象的类类型。换句话说,要创建什么类型的对象是从C++编译器角度编译时间的决定。如果我们将构造函数设为虚拟,编译器会标记一个错误。事实上,除了 内联 ,构造函数的声明中不允许使用其他关键字。

null

在实际场景中,我们需要基于一些输入在类层次结构中创建一个派生类对象。换句话说, 对象创建和对象类型是紧密耦合的,这迫使修改扩展。虚拟构造函数的目标是将对象创建与其类型分离 .

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

#include <iostream>
using namespace std;
//// LIBRARY START
class Base
{
public :
Base() { }
virtual // Ensures to invoke actual object destructor
~Base() { }
// An interface
virtual 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 END
class User
{
public :
// Creates Drived1
User() : 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 object
void Action()
{
pBase->DisplayAction();
}
private :
Base *pBase;
};
int main()
{
User *user = new User();
// Need Derived1 functionality only
user->Action();
delete user;
}


在上面的示例中,假设层次结构 基础 , 嘲笑 嘲笑 是库代码的一部分。班级 使用者 实用程序类试图利用层次结构。这个 主要的 功能正在消耗 基础 层次结构功能通过 使用者

这个 使用者 类构造函数正在创建 嘲笑 反对,永远反对。如果 使用者 消费者 主要的 在我们的情况下)需要 嘲笑 功能, 使用者 “需要创造” 新衍生2() “它迫使重新编译。重新编译是一种糟糕的设计方式,所以我们可以选择以下方法。

在讨论细节之前,让我们先回答一下,谁来决定创建 嘲笑 嘲笑 对象显然,它是 使用者 班这个 使用者 类可以使用if-else梯形图创建 嘲笑 嘲笑 ,如以下示例所示,

#include <iostream>
using namespace std;
//// LIBRARY START
class Base
{
public :
Base() { }
virtual // Ensures to invoke actual object destructor
~Base() { }
// An interface
virtual 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 END
class User
{
public :
// Creates Derived1 or Derived2 based on input
User() : pBase(nullptr)
{
int input; // ID to distinguish between
// Derived1 and Derived2
cout << "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 object
void Action()
{
pBase->DisplayAction();
}
private :
Base *pBase;
};
int main()
{
User *user = new User();
// Need either Derived1 or Derived2 functionality
user->Action();
delete user;
}


上面的代码*不*可扩展,是一种不灵活的设计。简单地说,如果库更新了 基础 具有新类的类层次结构 嘲笑 .你怎么能 使用者 类创建 嘲笑 对象一种方法是更新创建的if-else梯形图 嘲笑 基于新输入ID 3的对象,如下所示,

#include <iostream>
using namespace std;
class User
{
public :
User() : pBase(nullptr)
{
// Creates Drived1 or Derived2 based on need
int input; // ID to distinguish between
// Derived1 and Derived2
cout << "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 object
void Action()
{
pBase->DisplayAction();
}
private :
Base *pBase;
};


上述修改迫使 使用者 类重新编译,糟糕的(不灵活的)设计!而且不会关门 使用者 由于 基础 扩大

问题在于对象的创建。向层次结构中添加新类,强制 使用者 类重新编译。我们不能将创建对象的操作委托给类层次结构本身或虚拟行为的函数吗?通过将对象创建委托给类层次结构(或静态函数),我们可以避免对象之间的紧密耦合 使用者 基础 等级制度足够的理论,请参阅以下代码,

#include <iostream>
using namespace std;
//// LIBRARY START
class Base
{
public :
// The "Virtual Constructor"
static Base *Create( int id);
Base() { }
virtual // Ensures to invoke actual object destructor
~Base() { }
// An interface
virtual 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 Base
Base *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 objects
if ( id == 1 )
{
return new Derived1;
}
else if ( id == 2 )
{
return new Derived2;
}
else
{
return new Derived3;
}
}
//// LIBRARY END
//// UTILITY START
class User
{
public :
User() : pBase(nullptr)
{
// Receives an object of Base hierarchy at runtime
int 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 object
void Action()
{
pBase->DisplayAction();
}
private :
Base *pBase;
};
//// UTILITY END
//// Consumer of User (UTILITY) class
int main()
{
User *user = new User();
// Action required on any of Derived objects
user->Action();
delete user;
}


这个 使用者 类独立于对象创建。它将这一责任委托给了 基础 ,并以ID的形式提供输入。如果库添加了新类 嘲笑 ,库修改器将在内部扩展if-else阶梯 创造 返回正确的对象。消费者 使用者 由于扩展了 基础 .

请注意,函数 创造 用于返回不同类型的 基础 在运行时初始化对象。它的行为类似于虚拟构造函数,也称为 工厂法 在模式术语中。

模式世界展示了实现上述概念的不同方式。此外,上述代码还存在一些潜在的设计问题。我们的目标是提供一些关于虚拟构造的见解,根据一些输入动态创建对象。我们有关于这个主题的优秀书籍,感兴趣的读者可以参考它们以了解更多信息。

文基 。如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请发表评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享