问题描述
是否可以从抽象类的指针作为父类访问子类的函数成员? 这是抽象类
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) 并带来一些额外费用。
通常最好重新设计架构而不是沮丧。