- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
比较这两种技术的优点/缺点是什么?更重要的是:为什么以及何时应该使用一个而不是另一个?这只是个人品味/偏好的问题吗?
尽我所能,我还没有找到其他明确解决我问题的帖子。在有关多态性和/或类型删除的实际使用的许多问题中,以下似乎是最接近的,或者看起来如此,但它也没有真正解决我的问题:
C++ -& CRTP . Type erasure vs polymorphism
请注意,我非常了解这两种技术。为此,我在下面提供了一个简单、独立的工作示例,如果觉得不必要,我很乐意将其删除。但是,该示例应阐明这两种技术对我的问题的意义。我对讨论命名法不感兴趣。另外,我知道编译时和运行时多态性之间的区别,尽管我认为这与问题无关。请注意,我对性能差异的兴趣不大,如果有的话。但是,如果有一个基于性能的引人注目的论点,我会很好奇阅读它。特别是,我想听听实际上只能使用这两种方法之一的具体示例(无代码)。
看下面的例子,一个主要的区别是内存管理,对于多态性,它保留在用户端,而对于类型删除,它被巧妙地隐藏起来,需要一些引用计数(或提升)。话虽如此,根据使用场景,多态性示例的情况可能会通过使用带有 vector (?) 的智能指针来改善,尽管对于任意情况,这很可能证明是不切实际的 (?)。另一个可能支持类型删除的方面可能是通用接口(interface)的独立性,但为什么这会是一个优势(?)。
下面给出的代码已使用 MS VisualStudio 2008 进行了测试(编译和运行),只需将以下所有代码块放入单个源文件即可。它也应该在 Linux 上使用 gcc 编译,或者我希望/假设,因为我看不出为什么不 (?) :-) 为了清楚起见,我在这里拆分/划分了代码。
这些头文件应该足够了,对吧(?)。
#include <iostream>
#include <vector>
#include <string>
简单的引用计数来避免提升(或其他)依赖。该类仅在下面的类型删除示例中使用。
class RefCount
{
RefCount( const RefCount& );
RefCount& operator= ( const RefCount& );
int m_refCount;
public:
RefCount() : m_refCount(1) {}
void Increment() { ++m_refCount; }
int Decrement() { return --m_refCount; }
};
这是简单的类型删除示例/插图。它是从以下文章中复制和修改的。主要是我试图让它尽可能清晰和直接。 http://www.cplusplus.com/articles/oz18T05o/
class Object {
struct ObjectInterface {
virtual ~ObjectInterface() {}
virtual std::string GetSomeText() const = 0;
};
template< typename T > struct ObjectModel : ObjectInterface {
ObjectModel( const T& t ) : m_object( t ) {}
virtual ~ObjectModel() {}
virtual std::string GetSomeText() const { return m_object.GetSomeText(); }
T m_object;
};
void DecrementRefCount() {
if( mp_refCount->Decrement()==0 ) {
delete mp_refCount; delete mp_objectInterface;
mp_refCount = NULL; mp_objectInterface = NULL;
}
}
Object& operator= ( const Object& );
ObjectInterface *mp_objectInterface;
RefCount *mp_refCount;
public:
template< typename T > Object( const T& obj )
: mp_objectInterface( new ObjectModel<T>( obj ) ), mp_refCount( new RefCount ) {}
~Object() { DecrementRefCount(); }
std::string GetSomeText() const { return mp_objectInterface->GetSomeText(); }
Object( const Object &obj ) {
obj.mp_refCount->Increment(); mp_refCount = obj.mp_refCount;
mp_objectInterface = obj.mp_objectInterface;
}
};
struct MyObject1 { std::string GetSomeText() const { return "MyObject1"; } };
struct MyObject2 { std::string GetSomeText() const { return "MyObject2"; } };
void UseTypeErasure() {
typedef std::vector<Object> ObjVect;
typedef ObjVect::const_iterator ObjVectIter;
ObjVect objVect;
objVect.push_back( Object( MyObject1() ) );
objVect.push_back( Object( MyObject2() ) );
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
std::cout << iter->GetSomeText();
}
就我而言,这似乎使用多态实现了几乎相同的效果,或者可能不是(?)。
struct ObjectInterface {
virtual ~ObjectInterface() {}
virtual std::string GetSomeText() const = 0;
};
struct MyObject3 : public ObjectInterface {
std::string GetSomeText() const { return "MyObject3"; } };
struct MyObject4 : public ObjectInterface {
std::string GetSomeText() const { return "MyObject4"; } };
void UsePolymorphism() {
typedef std::vector<ObjectInterface*> ObjVect;
typedef ObjVect::const_iterator ObjVectIter;
ObjVect objVect;
objVect.push_back( new MyObject3 );
objVect.push_back( new MyObject4 );
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
std::cout << (*iter)->GetSomeText();
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
delete *iter;
}
最后是一起测试以上所有内容。
int main() {
UseTypeErasure();
UsePolymorphism();
return(0);
}
最佳答案
C++风格的基于虚拟方法的多态性:
基于 C++ 样式模板的类型删除(使用基于虚拟方法的多态性进行删除):
现在,哪个更好?好吧,这取决于在您的特定情况下上述事情是好是坏。
作为一个明确的例子,std::function<...>
使用类型删除,这允许它获取函数指针、函数引用、在编译时生成类型的一大堆基于模板的函数的输出、具有 operator() 的无数仿函数和 lambda。所有这些类型都彼此无关。而且因为它们与拥有 virtual operator()
无关。 , 当它们在 std::function
之外使用时context 他们所代表的抽象可以被编译掉。如果没有类型删除,您将无法做到这一点,而且您可能不想这样做。
另一方面,仅仅因为一个类有一个名为 DoFoo
的方法。 ,并不意味着他们都做同样的事情。有了多态性,它不仅仅是任何DoFoo
您正在打电话,但 DoFoo
从特定的界面。
至于您的示例代码...您的GetSomeText
应该是 virtual ... override
在多态的情况下。
没有必要仅仅因为您使用类型删除而引用计数。没有必要因为使用多态就不用引用计数。
您的Object
可以换行T*
就像你如何存储 vector
在另一种情况下是原始指针的 s,手动销毁它们的内容(相当于必须调用 delete)。您的 Object
可以包装 std::shared_ptr<T>
,在另一种情况下,您可以拥有 vector
的 std::shared_ptr<T>
.您的 Object
可以包含 std::unique_ptr<T>
,等价于具有 std::unique_ptr<T>
的 vector 在另一种情况下。您的 Object
的ObjectModel
可以从 T
中提取复制构造函数和赋值运算符并将它们暴露给 Object
, 为您的 Object
提供完整的值语义,对应于 vector
的 T
在你的多态情况下。
关于C++ 技术 : Type-Erasure vs. 纯多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13309927/
假设a是张量,那么有什么区别: 类型(a) a.类型 a.type() 我找不到区分这些的文档。 最佳答案 type 是 python 内置方法。 它将返回对象的类型。喜欢 torch.Tensor.
什么是 Type 1 的居民的例子?两者都不是 Type也不是Type的居民?在 Idris REPL 中进行探索时,我无法想出任何东西。 更准确地说,我正在寻找一些 x除了 Type产生以下结果:
我找到了一些资源,但我不确定我是否理解。 我找到的一些资源是: http://help.sap.com/saphelp_nw70/helpdata/en/fc/eb2ff3358411d1829f00
这两个函数原型(prototype)有什么区别? void apply1(double(f)(double)); void apply2(double(*f)(double)); 如果目标是将提供的函
http://play.golang.org/p/icQO_bAZNE 我正在练习使用堆进行排序,但是 prog.go:85: type bucket is not an expression
假设有一个泛型定义的方法信息对象,即一个方法信息对象,这样的方法Info.IsGenericMethodDefinition==TRUE:。也可以说它们也有一个泛型参数列表:。我可以使用以下命令获取该
在具有依赖类型的语言中,您可以使用 Type-in-Type 来简化语言并赋予它很多功能。这使得语言在逻辑上不一致,但如果您只对编程感兴趣而不对定理证明感兴趣,这可能不是问题。 在 Cayenne
根据 Nim 手册,变量类型是“静态类型”,而变量在内存中指向的实际值是“动态类型”。 它们怎么可能是不同的类型?我认为将错误的类型分配给变量将是一个错误。 最佳答案 import typetrait
假设您有以下结构和协议(protocol): struct Ticket { var items: [TicketItem] = [] } struct TicketItem { } prot
我正在处理一个 EF 问题,我发现它很难调试...以前,在我的系统中有一个表类型继承设置管理不同的用户类型 - 所有用户共有的一种根类型,以及大致基于使用该帐户的人员类型的几种不同的子类型。现在,我遇
这是我的 DBManager.swift import RealmSwift class DBManager { class func getAllDogs() -> [Dog] {
我正在尝试使用傅里叶校正图像中的曝光。这是我面临的错误 5 padded = np.log(padded + 1) #so we never have log of 0 6 g
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
请考虑以下设置: protocol MyProcotol { } class MyModel: MyProcotol { } enum Result { case success(value:
好吧,我将我的 python 项目编译成一个可执行文件,它在我的电脑上运行,但我将它发送给几个 friend 进行测试,他们都遇到了这个错误。我以前从未见过这样的错误。我使用 Nuitka 来编译代码
当我尝试训练我的模型时"ValueError: Type must be a sub-type of ndarray type"出现在 line x_norm=(np.power(x,2)).sum(
我尝试在另一个类中打断、计数然后加入对象。所以我构建协议(protocol): typealias DataBreaker = () -> [Double] typealias DataJoiner
我正在使用 VS 2015 更新 3、Angular 2.1.2、Typescript 2.0.6 有人可以澄清什么是 typings 与 npm @types 以及本月很难找到的任何其他文档吗? 或
我正在考虑从 VS2010 更改为 Mono,因此我通过 MoMA 运行我的程序集,看看我在转换过程中可能遇到多少困难。在生成的报告中,我发现我不断收到此错误: bool Type.op_Equali
主要问题 不太确定这是否可能,但由于我讨厌 Typescript 并且它使我的编码变得困难,我想我会问只是为了确定。 interface ISomeInterface { handler: ()
我是一名优秀的程序员,十分优秀!