关于c ++:如何从基类指针复制一个继承的类而不进行拼接?

how to copy an inherited class from its base class pointer without splicing?

我在尝试创建一个从指针到它的基类的类副本时遇到了一些困难。最好通过这个例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <vector>

class Base {
  public:
    Base() { }
    virtual void test() { std::cout <<"I am just the base class
"
; }
};

class First : public Base {
  public:
    First() { }
    void test() { std::cout <<"This is the First class
"
; }
};

class Second : public Base {
  public:
    Second() { }
    void test() { std::cout <<"This is the Second class
"
; }
};

int main() {
  First *f = new First();
  Second *s = new Second();

  // First, I keep a vector of pointers to their base class
  std::vector<Base *> ptrs;
  ptrs.push_back(f);
  ptrs.push_back(s);
  ptrs[0]->test();    // Properly calls the implemented virtual class by inheritor
  ptrs[1]->test();    // Properly calls the implemented virtual class by inheritor

  // Now, I want to *copy* the class without it being spliced to just the base class
  // from the ptrs vector (not from 'f')
  First *f2 = new First(*ptrs[0]);
}

我最后得到的错误是:

1
2
3
4
test.cpp: In function ‘int main():
test.cpp:35: error: no matching function for call to ‘First::First(Base&)
test.cpp:12: note: candidates are: First::First()
test.cpp:10: note:                 First::First(const First&)

是否有任何方法可以强制转换此指针来复制完整的对象,而不仅仅是基类?或者需要存储一个指向继承者的指针才能使其工作?


您可以这样做:

1
2
3
First *f2 = 0;
if ( typeid(*ptrs[0]) == typeid(First))
   f2 = new First(*dynamic_cast<First*>(ptrs[0]));

那应该管用。

但更好的方法是在基类中使用clone()虚拟函数,并将其实现为派生类:

1
2
3
4
5
6
7
8
9
10
11
12
class Base
{
  public:
    virtual ~Base() { } //virtual destructed added by me!
    virtual Base *clone() = 0;
};

class First : public Base
{
  public:
    virtual First *clone() { /* implement it */ }  //Covariant return type
};

1
2
3
First *f2 = 0;
if ( typeid(*ptrs[0]) == typeid(First))
   f2 = ptrs[0]->clone(); //no need to use new

需要注意的两点:

  • 我已经向基类添加了虚拟析构函数。查看此主题以了解您可能需要它的原因。
  • 我在派生类中对clone()使用了不同的返回类型。它被称为协变返回类型。

1
2
First *fx=(First*)ptrs[0];
First *f2 = new First(*fx);