【问题标题】:Passing inherited class type as argument将继承的类类型作为参数传递
【发布时间】:2014-06-05 11:26:13
【问题描述】:

我在将继承的类类型作为参数传递给采用其基类类型的方法时遇到问题。

class Base {...}
class Derived : public Base {...}
class Container {
    vector<Base*> cont; //1
 public:
    void addToCont(Base x) { //2
        cont.push_back(&x);
    }
}

int main() {
   Container c;
   c.addToCont(Derived(p1,p2)); //3
}

1) 我想我需要有指向对象的指针容器来保持它的工作

2) 这是从 Derived 到 Base 的转换错误

3) 我不应该改变这个电话。我试过了

Derived d(p1,p2);
c.addToCont(d);

addToCont(Base& x)

它对我有用。

我的问题是我有 3 个派生类,我不想重载 add 方法 3 次。我想我将不得不为这些类添加一些虚拟方法或一些类型转换,但我找不到任何相关信息。我是继承新手,对此很困惑。感谢您的所有帮助。

【问题讨论】:

  • 请发布您的真实代码,而不是这个充满语法错误和未声明标识符的伪 sn-p。见SSCCE
  • 重复摘要:您有未定义的行为,因为您正在存储指向临时对象的指针。

标签: c++ inheritance methods


【解决方案1】:

一些注意事项:

  1. 必须使用指向 Base 的指针向量,以便您可以处理层次结构中的对象。不用说,使用某种智能指针而不是原始指针可能会更好,但这与偏好和您对风险的热爱程度有关。
  2. 使用void addToCont(Base x) 是错误的,因为即使您只是添加一个 Base 对象,您也会添加一个指向局部变量的指针(按值传递参数)
  3. 使用void addToCont(Base &amp;x) 使用本地Derived d 的方式也是错误的,原因与以前相同,一旦d 超出范围,您就会留下一个悬空指针存储在指针
  4. 调用addToCont(Derived(...)) 传递一个临时对象。在考虑内存管理时必须考虑到这一点。
  5. 不知道为什么您认为需要为所有派生类重载 addToCont,这不是您在 void addToCont(Base &amp;x) 上所做的事情
  6. 解决方案(如果您保留原始指针)是在 void addToCont(Base *x) 那里您可以将指针传递给 Base 或任何 Derived。同样,您必须注意内存管理。您的 Derived 对象可能需要分配 new Derived(...),并且您必须注意谁拥有它,以及谁负责删除它(例如,当 Container 对象被销毁时)。
  7. 您可能应该记住将 virtual 作为 Base 的析构函数,因为您将从 Base 指针销毁 Derived 对象,如果析构函数不是虚拟的,则该对象只会被部分销毁。

如果addToCont(Derived(...)) 调用是绝对需要的,那么您可能要考虑使用void addToCont(Base &amp;x) 定义....但是它们,您必须先克隆对象,然后再将其插入向量:

void addToCont(const Base &x) { //2
    cont.push_back(x.clone());
}

但是.. 您需要在派生类中实现(至少)一个virtual Base *clone() const 方法,该方法将生成一个基指针,该指针具有派生对象的精确副本,涉及对象的额外副本和额外的克隆...

【讨论】:

    【解决方案2】:

    派生类只有在它们是引用或指针时才“可以使用”。如果您将一个类转换为没有引用或指针的基类,您以后将无法将其用作派生类。

    如果您实际上是在容器中存储指针,那么我会明确说明,所以:

    class Container {
        vector<Base*> cont;
     public:
        void addToCont(Base* x) { 
            cont.push_back(x);
        }
        ~Container()
        {
           for(auto a : cont)
           {
               delete a;
           }
        }
    }
    

    主要是:

    容器 c; c.addToCont(new Derived(p1,p2));

    请注意,在您的原始代码中,Derived(p1, p2) 将在调用addToCont(...) 后再次被销毁,因此您的数组将指向派生类的“死”元素。这可能不是您真正想要的(因为使用该元素是未定义的行为,并且构建一个充满无用元素的容器非常没有意义)

    【讨论】:

    • 好吧,我不应该更改 main 中的调用,所以它必须保持原样(没有新词)。我刚刚发现我应该能够为 addToCont 方法制作一个模板,我认为它会起作用
    • 那么你可能也不应该真正使用指针数组!
    • 那么我可以将所有派生对象存储在一个容器中吗?
    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    相关资源
    最近更新 更多