微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

抽象类访问其子类函数

如何解决抽象类访问其子类函数

是否可以从抽象类的指针作为父类访问子类的函数成员? 这是抽象类

class Item {
    public:
        virtual double getTotalPrice() = 0;
};

这是子类

class Product : public Item {
    protected:
        string name;
    public:
        Product() {}
        string getName() {}
        double getTotalPrice() {}
};

是否可以在主驱动程序中从 Item 类的实例访问此 getName() 函数,因为我还想显示总价和产品名称

解决方法

  • 如果您应该能够通过基类指针 virtual 对象,则需要您的基类具有 delete 析构函数。
  • 也让 getName virtual
class Item {
public:
    virtual ~Item() = default;
    virtual const string& getName() /* const */ = 0;
    virtual double getTotalPrice() /* const */ = 0;
};

请注意,您不允许更改的 Product 类存在轻微缺陷。

  • 它不会在它应该返回的地方返回值。
  • getter 成员函数不是 const

如果你不能自己做,建议一些改变:

class Product : public Item {
private: // prefer private member variables
    string name;
public:
    Product() = default;
    const string& getName() const override { return name; }
    double getTotalPrice() const override {
       // why is this implemented here when there's no price to return?
       return {};
    }
};
,

您不能拥有 abstract Item 类的实例(因为它是抽象的),但您可以拥有指向派生(和非)类的 Item 指针(或引用) -抽象)Product 类。

但是因为 Item 声明没有 getName() ,你可能需要做一个 dynamic_cast 来检查指针是否真的是一个 Product,例如。>

Item* item = new Product();
...

// at same later time or some ooter function:
// use dynamic_cast to check if the pointee is the type you expect it to be

Product* p = dynamic_cast<Product>(item);
if (p) p->getName();

虽然,不是直接针对您的问题,我认为这里也存在设计问题。像 Product 这样的东西由许多项目组成,所以它是 1:N 的组合关系。为了获得总价,一个概念(例如 Billable )将更合适。 所以我可能会建议类层次结构如下:

class Billable
{
public:
    virtual double getTotalPrice() const = 0;
    virtual ~Billable() {}
};

class Item : public Billable
{
    string name;
public:
    string getName() const { return name; }
    double getTotalPrice() const override { ... impl .. }
    // ... rest 
}

class Product : public Billable
{
    string name;
    vector<Items> items;
public:
    string getName() const { return name; }
    double getTotalPrice() const override
    {
         return accumulate(begin(items),end(items),[](auto i) { return i->getTotalPrice(); });
    }
    // ... rest ...
    
}
,

如果您确定指针指向类型为 Product 的实际对象,则可以进行静态转换;如果不确定并想先检查它,则可以进行动态转换。如果指针不指向派生类的对象,这将不起作用。

class Item {
    public:
        virtual double getTotalPrice() = 0;
};

class Product : public Item {
    protected:
        string name;
    public:
        Product() {}
        string getName() {return {};}
        double getTotalPrice() {return {};}
};

int main() {
    Product p;
    Item *i = &p;
    
    static_cast<Product *>(i)->getName();

    auto *ptr = dynamic_cast<Product *>(i);
    if (ptr) ptr->getName();
}

dynamic_cast 需要运行时类型信息 (RTTP) 并带来一些额外费用。

通常最好重新设计架构而不是沮丧。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。