【问题标题】:C++ storing derived classes in a single vector with the derived classes not containg redifined methodsC ++将派生类存储在单个向量中,派生类不包含重新定义的方法
【发布时间】:2015-08-11 09:03:13
【问题描述】:

我有一个具有相当复杂的继承结构的程序,所以我不会用它来展示我的问题,而是以下结构使用糟糕的样式来保持简单:

class A {
public:
    int va1;
    int va2;
    string va3;

    virtual void fa1(int x1, string x2) {
        // method body
    }

    int fa2 (bool y1, double y2) {
        // method body
    }

    A() {

    }

    virtual ~A() {

    }
};

class B :
    public A
{
public:
    bool ab1;
    double ab2;
    long double ab3;

    bool fb1(double x1) {
        //method body
    }

    long double fb2() {
        //method body
    }

    B(int z1) {
        ab2 = z1;
    }

    virtual ~B() {

    }
};

class C :
    public A
{
public:
    int ac1;

    long double fc1() {
              //method body
    }

    virtual void fa1(int x1, string x2) {
        // method body
    }

    C() {

    }

    virtual ~C() {

    }
};

如您所见,B 和 C 都主要由全新的变量和方法组成,而不是从 A 重新定义的变量和方法。 因此,将 A 指针与虚方法结合使用是行不通的。

直到现在,我一直对派生类使用单独的向量或数组,因为我很少编写主要由仅重新定义基类的方法的派生类组成的程序。

我知道我不能简单地创建一个 As 向量并放入 Bs 和 Cs 而不会丢失信息。

我的问题是,是否可以将 As、Bs 和 Cs 以指针或其他形式存储在单个向量中,并且仍然可以访问 A 中不存在的所有方法和变量?

如果它不适用于向量,是否有替代方案(可能是数组)?

代码可以包含现代 C++(标准、std::string 而不是 char* 等),因为不需要与 C 或传统 C++ 兼容。

【问题讨论】:

  • 您可以始终将所有内容存储为A*,然后尝试将dynamic_cast 设置为所需的派生类型。如果转换失败,那么你知道你不能调用这个函数。
  • 为什么将 A 指针与虚方法结合使用不起作用?另外,只需创建一个 As 的向量并放入 Bs 和 Cs,您会丢失哪些信息?
  • [OT] 从什么时候开始使用 std::string 变成“modern C++”了?!
  • 如果你有一个带有 virtual void example(int x) {} 的类 Base 和一个带有 virtual void example(int x) {} 的 Derived 类,则虚拟函数可以很好地工作。如何解决这个问题,我自己知道。但是如果我想访问 int notInBase(double x) {} 呢?由于在 Base 中没有调用类似的方法,现在(至少据我所知)可以使用 virtual 访问方法(来自 Derived)。
  • "[OT] 从什么时候开始使用 std::string 变成了“现代 C++”?!"我仍然看到大多数 C++ 程序员使用或推荐使用 char* 或 char[] 代替字符串,即使不使用 WindowsAPI 或其他遗留代码也是如此。但也许我认识错误的人并访问了一些不一般的网站。但这并不重要。我只是想确保我对新的 C++ 标准和非 C 兼容习惯没有问题,因为它不会破坏我的程序。

标签: c++ inheritance vector derived-class base-class


【解决方案1】:

这可以使用指针向量或更好的向量来完成,shared_ptr 这样的向量:

vector<shared_ptr<A>> v;        // vector of shared ponters to A
v.push_back(make_shared<A>());
v.push_back(make_shared<B>(2));
v.push_back(make_shared<C>());

shared_ptr<A> pa = v[1];       // this one is a B but in real life we would'nt know
                               // I can use all the A methods without question
shared_ptr<B> pb = dynamic_pointer_cast<B>(pa);   // attempt to cast it to a B
if (pb) {                     // if casting succeded
    pb->fb2();                       // I call the B method 
} else cout << "Not a B"<<endl; // if not, I know that it's an A but not a B

原则是你存储在向量(共享)指向 A 的指针中。所以你总是可以访问它的 A:: 成员。

由于您的基类是多态的(即它至少具有一个虚函数),因此可以使用 dynamic_castshared_ptr 的情况下为 dynamic_pointer_cast)尝试将指针强制转换为派生类的指针(例如 B)。如果转换成功(非空指针),那么您就知道您可以访问B:: 成员。

shared_ptr 与原始指针的使用有助于内存管理:如果一个对象不再使用,它​​会被自动删除。

这里是 online demo

【讨论】:

  • 谢谢,我试试看。
  • 您会说使用这样的向量是个好主意,还是在大多数情况下,它比实际价值更麻烦?例如,在我的程序中,将不同的派生类存储在它们自己的向量中绝对是一种可能,只要我添加一些开关、if 语句等。
  • @Willi 我添加了一个在线演示的链接。不知道你的程序做了什么,很难给出一个客观的答案,但总的来说,像这样使用向量是一个非常好的主意。稍后您可以轻松地添加新的派生类。可能你也看看访问者设计模式。
猜你喜欢
  • 2021-11-22
  • 2014-02-19
  • 1970-01-01
  • 2019-05-13
  • 2011-11-15
  • 1970-01-01
  • 2018-09-17
  • 2016-07-03
  • 2020-02-11
相关资源
最近更新 更多