要实现多态,我们需要使用指向派生类实例的基类指针。多态性的一切都很好,除非每个派生类都有一个或几个自己的成员函数?如果基类指针不能访问这些派生类成员函数,那么多态性有什么方便的呢?
下面是一个例子。"shape“是一个基类。"square“和"circle”是两个派生类。
class shape {
public:
virtual void getArea()=0;
};
class square: public shape {
private:
int edge;
public:
square(){edge = 1;}
virtual void getArea(){ //polymorphism
cout << edge*edge << "\n";
}
void getNumberOfEdge(){ //a new member function
cout << "4\n";
}
};
class circle: public shape {
private:
int radius;
public:
circle(){radius = 1;}
virtual void getArea(){ //polymorphism
cout << 3*radius*radius << "\n";
}
void getCurvature(){ //a new member function
cout << 1/radius << "\n";
}
};
int main(){
shape* arr[2] = {
new square(),
new circle()
};
arr[0]->getArea();
arr[1]->getArea();
arr[0]->getNumberOfEdge(); //compiler error
}
getArea()是实现多态性的一个很好的例子。然而,访问派生类成员函数会给我带来编译器错误,我完全理解其中的原因。
发布于 2019-10-04 05:49:01
基类中的功能应该在基类中。特定于特定派生类的功能应该包含在这些派生类中。virtual
函数允许代码操作形状并执行对任何形状有效的操作,而不必了解如何在现在和将来可能存在的每种形状类型上执行这些函数。
但是从设计的角度来看,我们不想仅仅为了每个派生类而向基类添加一堆虚函数,对吧?
如果这些操作在基类上是有意义的,那么它们可能应该放在基类上。如果它们是特定于形状的,则它们属于该功能有意义的特定类。
假设您有一个使用形状的系统,但没有八角形的派生类。多态性的要点是,今天可以编写代码,如果有人添加了八角形,这些代码将在以后的八角形上完美工作。
发布于 2019-10-04 05:51:55
有了适当的类型,你就可以很好地处理边缘问题的数量,把多态性带到边缘!
让我们添加一个类:
// a base interface for all Edged shapes
struct HasEdges {
virtual void getNumberOfEdges() const = 0;
// side note: I'd prefer this getter to return an int
// but keeping it as in the example
};
现在是Square (但不是Circle!)我们可以这样做:
class Square: public Shape, public HasEdges {
// ...
public:
void getNumberOfEdges() const override { /* implement */ }
// ...
};
main是这样的:
int main(){
shape* arr[2] = {
new square(),
new circle()
};
arr[0]->getArea();
arr[1]->getArea();
// some edgy thing below
HasEdges* hasEdges = dynamic_cast<HasEdges*>(arr[0]);
// above returns null on failure
if(hasEdges) hasEdges->getNumberOfEdges();
// releasing memory...
}
发布于 2019-10-04 05:54:20
运行时多态意味着运行时的多态行为。getArea()
定义的行为在运行时根据它所指向的实例进行更改。所以,你把多态性和静态编译问题混在一起了。基类没有名为getNumberOfEdge()
的成员函数,因此会出现编译器错误。
如果你想调用特定的实现,为什么不让编译器看到它并转换它呢?
public:
virtual void getArea()=0;
template<typename T>
const T * get() {
return dynamic_cast<T *>(this);
}
};
现在您可以将其强制转换为任何派生类型:
auto square_instance = arr[0]->get<square>();
if (square_instance) {
square_instance->getNumberOfEdge();
}
A different approach to run time polymorphism is suggested by Sean Parent.我喜欢它,并且现在更多地尝试这种方法。
https://stackoverflow.com/questions/58227169
复制相似问题