【问题标题】:Inheritance and pointers继承和指针
【发布时间】:2017-12-07 18:56:59
【问题描述】:

我有这样的代码:

class Human
{
    protected:
        int age;
        std::string sex;    
    public: 
        virtual void speak() = 0;
};
class Child:public Human
{
    public:
        void speak(){std::cout << "I am Child\n";}
};
class Man:public Human
{
    public: 
        void speak(){std::cout << "I am Man\n";}
};
class Woman:public Human
{
    public: 
        void speak(){std::cout << "I am Woman\n";}
};
(don't know, std::shared_ptr<Human> maybe?) operator*(std::shared_ptr<Child> &b, int x)
{
    b->setAge(b->getAge()+x);
    if(b->getAge()>18 && b->getSex()=="Man")
    {
        return (i want b to become std::shared_ptr<Man>)
    }
    if(b->getAge()>18 && b->getSex()=="Woman")
    {
        return (here I want b to become std::shared_ptr<Woman>);
    }
    return;
}
int main(){
    auto x = std::make_shared<Child>;
    x*19;
}

我知道这看起来很奇怪,但这是我能想到的最简单的情况,无需写下我在 rn 上苦苦挣扎的所有代码。有人可以解释一下,应该重载什么类型以及如何更改 shared_ptr 类型,知道它们是从同一个父级派生的吗?

【问题讨论】:

  • 您是在问如何为shared_ptr 本身定义运算符重载吗?
  • 无论你放什么类型,这个特定的代码都不会构建。用一个简短的段落描述您希望达到的目标怎么样?
  • @OliverCharlesworth 不,只是想知道是否可以将 ptr 类型从 b 更改为 c 如果它们都派生自同一个类,以及方法是否可以返回 ptr 或 ptr ,取决于 if 语句
  • 我的意思是,x*8 无法编译 - xshared_ptr
  • @OliverCharlesworth - x 成为 shared_ptr 本身并不是一个障碍。将操作符参数类型从 B 更改为 shared_ptr&lt;B&gt; 完全没问题。

标签: c++ oop inheritance std shared-ptr


【解决方案1】:

对象不能改变类型。 Child 对象将始终是 Child 对象。您可以做的是创建一个具有您想要的属性的 new 对象并返回:

std::shared_ptr<Human> operator*(std::shared_ptr<Human> b, int x)
{
    b->setAge(b->getAge()+x);
    if(b->getAge()>18 && b->getSex()=="Man") {
        return std::make_shared<Man>(b->getAge());
    } else if(b->getAge()>18 && b->getSex()=="Woman") {
        return std::make_shared<Woman>(b->getAge());
    } else {
       return b;
    }
}

int main(){
    std::shared_ptr<Human> x = std::make_shared<Child>;
    x = x*19;
}

不过,这似乎不是一个好的设计。 Human 的儿童或成人状态最好表示为对象的属性或检查 age 是否大于 18 的函数。

【讨论】:

  • 我有 75% 的把握确定我尝试过这种变体,但它不起作用,因为 x 是编译器方面的 std::shared_ptr,而不是 std::shared_ptr,至少在 c++11 中。
  • 但现在您可以将此运算符与 std::shared_ptr x = std::make_shared AND std::shared_ptr x = std::make_shared
【解决方案2】:

您不能使类型 T&lt;Derived&gt; 继承自 T&lt;Base&gt;,因为 C++ 模板不支持协变。这样做对于某些类型是不安全的,例如对容器的可变引用。 (想象一下将std::vector&lt;Cat&gt; 引用为std::vector&lt;Animal&gt;&amp; 并推回一条狗!)

(我会将这个答案设为评论,但我没有评论能力。)

更新: 您可以编写处理堆数据的非模板包装器:

class Wrapper
{
public:
  Wrapper(Base* b) : raw(b) {}
  ~Wrapper() { delete raw; }
  Base& get() { return *base; }
private:
  Base* raw;
}

当然,在您的示例中,您使用的是 std::shared_ptr 而不是 std::unique_ptr。您必须处理引用计数,而不是简单地删除析构函数中的数据,但保持内部原始指针的技术仍然有效。

更新 2:

上面的代码可以按原样使用以提供一定程度的间接性,这样从基类继承的所有类都可以保存在同一类型中,而无需编写自己的引用计数器:

std::shared_ptr&lt;Wrapper&gt;

这个解决方案可以看作类似于std::shared_ptr&lt;Base*&gt;,只是后一种解决方案会泄漏内存。

【讨论】:

  • 滥用回复机制进行评论将无法获得评论权限。
  • 我很抱歉。我觉得我的帖子在某种程度上是一个答案,但觉得它更适合作为评论。我应该删除它吗?
  • 如果你想回答,无论如何。但不要发布你想要的评论。所以是的,如果您愿意,可以将其改进为答案。
  • 我添加了一个更好的解决方案。你会说我改进了我的答案吗?
猜你喜欢
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 2012-01-27
  • 2014-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多