2016-08-30 106 views
7

说我有一个类:是否可以在同一个类中创建一个类的实例?

class Foo{ 
public: 

    Foo(){ 
    } 

    //Is it possible to create a function like this: 
    virtual Foo* createOb(){ 
     //Should create a new Foo,Bar or Fiz, depending on the actual object type. 
    } 
} 

class Bar: public Foo{ 
public: 

    Bar(){ 
    } 
} 

class Fiz: public Foo{ 
public: 

    Fiz(){ 
    } 
} 

是否有可能有一个方法createOb()在基类的,所以当createOb()被调用所导出的类之一的实例,其的一个实例派生类是否被创建?

+0

如果您在不同的cpp文件我想这应该有可能分裂它。你是否正在寻找基类的克隆函数而不知道它是什么子类?你可以看看这种方法:https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/ – Hayt

+0

@ c.bear但是Foo不知道派生类......我是C++的新手,所以我不知道你的意思...... –

回答

5

是的目的,这是可以做到,使用CRTP

首先,返回从new获得的原始指针是非常危险。在c++中,只有当原始指针不具有指向对象的所有权时,才应使用原始指针。所以我冒昧地使用unique_ptr

struct Base { 
    virtual auto create_obj() -> std::unique_ptr<Base> 
    { 
    return std::unique_ptr<Base>{}; 
    } 
}; 

// abstract works too: 
struct Base { 
    virtual auto create_obj() -> std::unique_ptr<Base> = 0; 
}; 

template <class Derived> 
struct Base_crtp : Base { 
    auto create_obj() -> std::unique_ptr<Base> override /* final */ 
    { 
    return std::unique_ptr<Base>{new Derived{}}; 
    } 
}; 

struct D1 : Base_crtp<D1> 
{ 
}; 

struct D2 : Base_crtp<D2> 
{ 
}; 

然后:

auto b1 = std::unique_ptr<Base>{new D1{}}; 
auto b2 = std::unique_ptr<Base>{new D2{}}; 

auto new_d1 = b1->create_obj(); 
auto new_d2 = b2->create_obj(); 
+0

可能不是每个人都会得到的东西是如何采用它来复制构造函数(在'create_obj'中将'this' ptr转换为'Derrived'。不知道在别人使用此解决方案的情况下是否可以帮助添加它所以这将是'返回std :: unique_ptr {新的派生{static_cast (* this)}};'如果需要的话 – Hayt

+0

@Hayt'克隆'在维基页面中有例子我链接 – bolov

+0

阿好了。没有看到那是一个链接:) – Hayt

0

不,这是不可能的“纯”继承。这些类必须重写createOb()成员函数才能支持克隆。

你可以看到为什么这是不可能的考虑分开编译类。一窍不通的createOb()成员函数的实现必须与BarFiz分开完成,这使得基类不可能知道其子类的类型。但是,在基础中使用纯虚函数的实现非常普遍。

另一种方法是使用好奇地循环模板模式(CRTP)来实现克隆。这article解释了如何完成。

+0

根据情况,基于CRTP的方法也很常见。但是看到约翰是C++的新手,这可能会让初学者感到困惑。 – Hayt

+0

@Hayt我已经在使用类似CRTP的东西了,但是对于我来说我的头很难缠。我更喜欢简单的东西,即使它是黑客,只要它正常工作。 –

+0

听起来就像我将不得不更新所有派生类! :(太多了...... –

0

这不是一个最佳的解决方案,但它的工作原理。

在您的.h

class Foo{ 
public: 
    Foo(); 
    virtual Foo* createOb(); 
}; 

class Bar: public Foo{ 
public: 
    Bar(); 
}; 

class Fiz: public Foo{ 
public: 
    Fiz(); 
}; 

在你的.cpp

#include "Header.h" 

Foo::Foo() {} 

Foo* Foo::createOb(){ 
    if (dynamic_cast<Bar*>(this)) { 
     return new Bar(); 
    } 
    else if (dynamic_cast<Foo*>(this)) { 
     return new Foo(); 
    } 
    return nullptr; 
} 

Bar::Bar() {} 
Fiz::Fiz() {} 

正如已经建议请考虑一个纯虚方法

+0

似乎约翰有很多“兴旺的班级,虽然 – Hayt

+0

问题是,Foo将不得不知道酒吧,Fiz等的存在...我要去尝试黑客一起宏... XD –

+0

海耶是正确....我有很多派生类,并将继续添加更多! –

1

肯定是有的!

当一个方法在基类中声明为虚拟并通过派生类对象调用时,派生类函数被调用(在vC++中读取vprt,vtable概念)。

#include <iostream> 

using namespace std; 

class A{ 
     public: 
     virtual A* getobj(){ 
     return new A(); 
     } 
}; 
class B: public A{ 
     public: 
     B(){cout<<"B constructor"<<endl;} 
     virtual A* getobj(){ 
     return new B(); 
     } 
}; 

int main() 
{ 

A *a = new B(); 
A *second = a->getobj(); 
return 0; 
} 

在上面的代码中,我们使用类B的对象调用getobj()函数。 这里B类的构造函数被调用两次。

  1. 第一,新的B()在主

  2. 其次用于getobj函数调用,它再次产生乙

+0

我认为ideea是不在每个派生类中编写相同的代码。只需在基类中拥有'getobj'的代码 – bolov

+0

这两个函数都应该在类 –

+2

中这里的问题是John有很多类。所以你需要添加这100个以上的课程。这是他想要避免的。 – Hayt

相关问题