【问题标题】:Base class parameter in a derived class' method派生类方法中的基类参数
【发布时间】:2021-07-06 14:44:48
【问题描述】:

这是我的代码:

class Base
{
    virtual shared_ptr<Base> clone() const = 0;
};
class A : public Base
{
public:
    A(const string &str) {
    _str = str;
    }
    shared_ptr<Base> clone() const
    {
        return make_shared<A>(*this);
    }
private:
    string _str;
};

class B : public Base 
{
public:
    B() { }
    B &AddToStorage(const string &key, Base &&val)
    {
        //_storage[key] = val; ?
        //_storage[key] = val.clone(); ?
        return *this;
    }
    shared_ptr<Base> clone() const
    {
        return make_shared<B>(*this);
    }
private:
    map<string, shared_ptr<Base>> _storage;
};

注意类 B 和它的方法 AddToStorage。如何使用 A 类和 B 类调用此函数?如:

B test;
test.AddToStorage("a", A("test1"));
test.AddToStorage("b", A("test2"));
test.AddToStorage("c", B());

当我访问 _storage (map) 时,我以后如何区分 A 类和 B 类?

编辑:我尝试实现克隆,但失败了 - https://www.fluentcpp.com/2017/09/08/make-polymorphic-copy-modern-cpp/ 遵循本教程,但似乎有一个错误“没有匹配函数调用 'A::A(const B&)'”

【问题讨论】:

    标签: c++ class inheritance


    【解决方案1】:

    如何同时使用 A 类和 B 类调用此函数?

    std::shared_ptr&lt;A&gt;std::shared_ptr&lt;B&gt; 都可以转换为 std::shared_ptr&lt;Base&gt;,这是您的函数所期望的,因此提供共享指针将起作用。

    test.AddToStorage("a", std::make_shared<A>("test1"));
    test.AddToStorage("b", std::make_shared<A>("test2"));
    test.AddToStorage("c", std::make_shared<B>());
    

    当我访问 _storage (map) 时,我以后如何区分 A 类和 B 类?

    为了区分它们,您需要在Base 中有一个虚函数,并且(理想情况下)在AB 中覆盖它以执行不同的操作。使用完全没有虚函数的指针管理类层次结构是相当可疑的,因此您可能至少应该拥有一个。

    【讨论】:

    • 拥有一个虚拟析构函数就足够了(通常应该用于任何类型的多态层次结构)。至于区分,虚拟方法更可取,但也可以使用dynamic_cast,或者shared_ptrstd::dynamic_pointer_cast
    【解决方案2】:

    添加到其他答案。如果你编译你的代码:

    test.AddToStorage("c", B());
    

    这些错误很有帮助:

    no viable conversion from 'B' to 'std::shared_ptr<Base>'
    

    您传入的是B 的实际对象,而不是指向 B 的指针。现在可以尝试将其更改为

    test.AddToStorage("c", new B());
    

    但由于shared_ptr 的构造函数在这里

    被标记为显式。所以唯一的出路就是做类似的事情

    test.AddToStorage("c", std::make_shared<B>());
    

    至于检测类型,正如另一个答案所暗示的那样,拥有一个虚拟继承层次结构将是一个好主意。如果您启用了 RTTI(通常默认启用),您还可以使用 type_index 之类的东西,它是运行时 type_info 的包装器,可用于对容器进行索引。

    std::unordered_map<std::type_index, std::string> type_names;
    type_names[std::type_index(typeid(A))] = "A";
    

    然后从一个

    shared_ptr<A> pA;
    std::cout<<type_names[std::type_index(typeid(*pA))]<<'\n';
    

    【讨论】:

    • 这听起来可能很愚蠢,但有没有办法让我只改变方法(而不是第二个 sn-p)?我听说过克隆模式,但无法让它们发挥作用..
    • @Ventuaer 要按原样保留第二个 sn-p,该方法必须采用 Base&amp;&amp; 而不是 shared_ptr&lt;Base&gt;,但实际上将 val 对象存储在 map正确地,您需要实现克隆。如果您对此有疑问,那么您需要编辑您的问题以显示您尝试过的对您不起作用的方法。
    • @Remy Lebeau 不幸不得不编辑它:(
    • @Ventuaer 仅供参考,const Base &amp;val 也可以。但无论哪种方式,_storage[key] = val.clone(); 都可以正常工作。真正的问题是您的 clone() 方法正在尝试调用您根本没有实现的复制构造函数。此外,显示的代码与您声称收到的错误消息不匹配,因为没有从 B 对象构造的 A 对象。
    猜你喜欢
    • 2018-05-16
    • 2019-07-25
    • 1970-01-01
    • 2014-03-17
    • 2014-09-05
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    相关资源
    最近更新 更多