Hierarquia Forma. Implemente a hierarquia Forma
projetada no Exercício 20.7 (que é baseada na hierarquia
da Figura 20.3). Cada FormaBidimensional deverá
conter a função retArea para calcular a área da forma
bidimensional. Cada FormaTridimensional deverá ter
funções-membro retArea e retVolume para calcular a
área e o volume, respectivamente, da forma tridimensional.
Crie um programa que use um vetor de ponteiros
Forma para objetos de cada classe concreta na hierarquia.
O programa deverá imprimir o objeto ao qual cada elemento
vetor aponta. Além disso, no loop que processa
todas as formas no vetor, determine se cada forma é uma
FormaBidimensional ou uma FormaTridimensional.
Se a forma for uma FormaBidimensional, mostre
sua área. Se a forma for uma FormaTridimensional,
mostre sua área e seu volume.
Passo 1
Vamos implementar a seguinte hierarquia Shape:
'slader'
Em primeiro lugar, vamos fazer a classe base "abstract/interface" Shape que será puramente virtual e armazenará apenas bibliotecas:
#ifndef H_SHAPE_H
#define H_SHAPE_H
#include cmath>
class Shape {
public:
virtual double getArea() const = 0;
};
Forma bidimensional
Esta classe será uma classe abstrata pura com a função getArea():
#ifndef H_TWODIMENSIONALSHAPE_H
#define H_TWODIMENSIONALSHAPE_H
#include "Shape.h"
class TwoDimensionalShape : public Shape {
public:
virtual double getArea() const = 0;
};
Elipse
Esta classe possuirá dois membros de dados protegidos representando comprimentos de eixo. Os membros de dados serão protegidos porque a classe derivada Circle também deve poder usá-los livremente (ambos os valores são iguais ao raio do círculo).
#ifndef H_ELLIPSE_H
#define H_ELLIPSE_H
#include "TwoDimensionalShape.h"
class Ellipse : public TwoDimensionalShape {
public:
Ellipse(double a, double b);
double getArea() const;
protected:
double a;
double b;
};
A área da elipse é igual ao produto do eixo menor e maior multiplicado por pi:
A implementação:
#include cmath>
#include "Ellipse.h"
Ellipse::Ellipse(double a, double b) : a(a), b(b) {}
double Ellipse::getArea() const {
return M_PI * a * b;
}
Passo 2
Como um círculo é uma elipse com um eixo maior/menor igual ao raio do círculo, podemos definir os dois valores para o raio e reutilizar toda a classe da seguinte maneira:
#ifndef H_CIRCLE_H
#define H_CIRCLE_H
#include "Ellipse.h"
class Circle : public Ellipse {
public:
explicit Circle(double radius);
};
#en
Fórmula da área do círculo:
A implementação:
#include "Circle.h"
Circle::Circle(double radius) : Ellipse(radius, radius) {}
Polígono
Esta classe servirá como uma classe vazia pai de rótulo:
#ifndef H_POLYGON_H
#define H_POLYGON_H
#include "TwoDimensionalShape.h"
class Polygon : public TwoDimensionalShape {
};
#endif
Observação: excluiremos a classe n-gon shapes para simplificar a tarefa.
Triângulo
A classe triângulo representará uma forma de triângulo e calculará a área por meio de uma fórmula genérica:
#ifndef H_TRIANGLE_H
#define H_TRIANGLE_H
#include "Polygon.h"
class Triangle : public Polygon {
public:
Triangle(double a, double b, double c);
double getArea() const;
protected:
double a;
double b;
double c;
};
#endif
Para calcular a área, usaremos a fórmula de Heron com o diâmetro
#include "Triangle.h"
Triangle::Triangle(double a, double b, double c) : a(a),
b(b),
c(c) {}
double Triangle::getArea() const {
double s = (a + b + c) / 2;
return sqrt(s * (s - a) * (s - b) * (s - c));
}
Passo 3
Agora vamos derivar outras classes da classe Triangle.
Os tipos de triângulos que vamos incluir são os triângulos equiláteros e isósceles porque dependem dos comprimentos dos lados, enquanto os demais tipos dependem dos ângulos, que não incluiremos para simplificar a tarefa.
Triângulo Equilátero
Declaração de classe:
#ifndef H_EQUILATERALTRIANGLE_H
#define H_EQUILATERALTRIANGLE_H
#include "Triangle.h"
class EquilateralTriangle : public Triangle {
public:
explicit EquilateralTriangle(double a);
};
#endif
Implementação da classe:
#include "EquilateralTriangle.h"
EquilateralTriangle::EquilateralTriangle(double a)
: Triangle(a, a, a) {}
Triângulo isósceles
Declaração de classe:
#ifndef H_ISOSCELESTRIANGLE_H
#define H_ISOSCELESTRIANGLE_H
#include "Triangle.h"
class IsoscelesTriangle : public Triangle {
public:
explicit IsoscelesTriangle(double a, double b);
};
#endif
Passo 4
Implementação da classe:
#include "IsoscelesTriangle.h"
IsoscelesTriangle::IsoscelesTriangle(double a, double b)
: Triangle(a, a, b) {}
Quadrilátero
Esta classe servirá como uma classe vazia pai:
#ifndef H_QUADRILATERAL_H
#define H_QUADRILATERAL_H
#include "Polygon.h"
class Quadrilateral : public Polygon {
};
#endif
trapézio
A classe vai armazenar os lados da base da forma com a adição da altura (distância entre os lados paralelos), que será usada no cálculo da área:
#ifndef H_TRAPEZOID_H
#define H_TRAPEZOID_H
#include "Quadrilateral.h"
class Trapezoid : public Quadrilateral {
public:
Trapezoid(double base1, double base2, double height);
double getArea() const;
private:
double base1;
double base2;
double height;
};
#endif
Fórmula que usaremos para calcular a área do trapézio (a e b são lados da base):
#include "Trapezoid.h"
Trapezoid::Trapezoid(double base1, double base2,
double height)
: base1(base1), base2(base2), height(height) {}
double Trapezoid::getArea() const {
return ((base1 + base2) / 2) * height;
}
Pipa
Para esta classe, armazenaremos apenas os comprimentos diagonais:
#ifndef H_KITE_H
#define H_KITE_H
#include "Quadrilateral.h"
class Kite : public Quadrilateral {
public:
Kite(double p, double q);
double getArea() const;
private:
double p;
double q;
};
#endif
Passo 5
Fórmula da área de uma pipa:
#include "Kite.h"
Kite::Kite(double p, double q) : p(p), q(q) {}
double Kite::getArea() const {
return p * q / 2;
}
Retângulo
Para simplificar a tarefa, derivaremos apenas as classes Rectangle e Square.
#ifndef H_RECTANGLE_H
#define H_RECTANGLE_H
#include "Quadrilateral.h"
class Rectangle : public Quadrilateral {
public:
Rectangle(double a, double b);
double getArea() const;
protected:
double a;
double b;
};
#endif
A=ab
#include "Rectangle.h"
Rectangle::Rectangle(double a, double b) : a(a), b(b) {}
double Rectangle::getArea() const {
return a * b;
}
Quadrado
Vamos simplesmente inicializar tanto Rectangle::a quanto Rectangle::b para um único comprimento e reutilizar a classe inteira:
#ifndef H_SQUARE_H
#define H_SQUARE_H
#include "Rectangle.h"
class Square : public Rectangle {
public:
explicit Square(double a);
};
#endif
A implementação:
#include "Square.h"
Square::Square(double a) : Rectangle(a, a) {}
Passo 6
Forma Tridimensional
A declaração de classe (classe abstrata pura):
#ifndef H_THREEDIMENSIONALSHAPE_H
#define H_THREEDIMENSIONALSHAPE_H
#include "Shape.h"
class ThreeDimensionalShape : public Shape {
public:
virtual double getSurfaceArea() const = 0;
virtual double getVolume() const = 0;
};
#endif
Cone
A classe armazenará o raio e a altura da forma do cone:
#ifndef H_CONE_H
#define H_CONE_H
#include "ThreeDimensionalShape.h"
class Cone : public ThreeDimensionalShape {
public:
Cone(double radius, double height);
double getArea() const;
double getVolume() const;
private:
double radius;
double height;
};
#endif
Área de superfície do cone:
Volume do cone:
#include "Cone.h"
Cone::Cone(double radius, double height)
: radius(radius), height(height) {}
double Cone::getArea() const {
return M_PI * radius * (radius
+ sqrt(pow(height, 2.0) + pow(radius, 2.0)));
}
double Cone::getVolume() const {
return M_PI * pow(radius, 2.0) * height / 3;
}
Poliedro
Esta classe servirá como uma classe vazia pai de rótulo:
#ifndef SLADERC_POLYHEDRON_H
#define SLADERC_POLYHEDRON_H
#include "ThreeDimensionalShape.h"
class PolyHedron : public ThreeDimensionalShape {
};
#endif
Nota: Vamos pular a derivação do prisma e incluir apenas a derivação do cubo de sólidos platônicos para simplificar a tarefa.
Pirâmide
A classe conterá o comprimento, a largura e a altura da forma da pirâmide:
#ifndef H_PYRAMID_H
#define H_PYRAMID_H
#include "PolyHedron.h"
class Pyramid : public PolyHedron {
public:
Pyramid(double length, double width, double height);
double getArea() const;
double getVolume() const;
private:
double length;
double width;
double height;
};
#endif
Passo 7
Área de superfície da pirâmide:
#include "Pyramid.h"
Pyramid::Pyramid(double length, double width,
double height) : length(length),
width(width),
height(height) {}
double Pyramid::getArea() const {
return length * width + length
* sqrt(pow((width / 2), 2.0)
+ pow(height, 2.0))
+ width * sqrt(pow((length / 2), 2.0)
+ pow(height, 2.0));
}
double Pyramid::getVolume() const {
return length * width * height / 3;
}
Cubo
Declaração de classe:
#ifndef H_CUBE_H
#define H_CUBE_H
#include "PolyHedron.h"
class Cube : public PolyHedron {
public:
explicit Cube(double a);
double getArea() const;
double getVolume() const;
private:
double a;
};
#endif
Área de superfície do cubo:
Volume do cubo:
#include "Cube.h"
Cube::Cube(double a) : a(a) {}
double Cube::getArea() const {
return 6 * pow(a, 2.0);
}
double Cube::getVolume() const {
return pow(a, 3.0);
}
Cilindro
Declaração de classe:
#ifndef H_CYLINDER_H
#define H_CYLINDER_H
#include "ThreeDimensionalShape.h"
class Cylinder : public ThreeDimensionalShape {
public:
Cylinder(double radius, double height);
double getArea() const;
double getVolume() const;
private:
double radius;
double height;
};
#endif
Área de superfície do cilindro:
Volume do cilindro:
#include "Cylinder.h"
Cylinder::Cylinder(double radius, double height) : radius(
radius), height(height) {}
double Cylinder::getArea() const {
return 2 * M_PI * radius * height
+ 2 * M_PI * pow(radius, 2.0);
}
double Cylinder::getVolume() const {
return M_PI * pow(radius, 2.0) * height;
}
#include "Cylinder.h"
Cylinder::Cylinder(double radius, double height) : radius(
radius), height(height) {}
double Cylinder::getArea() const {
return 2 * M_PI * radius * height
+ 2 * M_PI * pow(radius, 2.0);
}
double Cylinder::getVolume() const {
return M_PI * pow(radius, 2.0) * height;
}
Área de superfície da esfera:
Volume da esfera:
#include "Sphere.h"
Sphere::Sphere(double radius) : radius(radius) {}
double Sphere::getArea() const {
return 4 * M_PI * pow(radius, 2.0);
}
double Sphere::getVolume() const {
return 4 * M_PI * pow(radius, 3.0) / 3;
}
Por fim, o arquivo principal para fins de demonstração.
Cabeçalho do arquivo (incluindo as "folhas" da árvore hierárquica é o mínimo):
#include iostream>
#include
#include "Circle.h"
#include "EquilateralTriangle.h"
#include "IsoscelesTriangle.h"
#include "Trapezoid.h"
#include "Kite.h"
#include "Square.h"
#include "Cone.h"
#include "Pyramid.h"
#include "Cube.h"
#include "Cylinder.h"
#include "Sphere.h"
using namespace std;
...
Declare e inicialize objetos e coloque-os em um vetor:
int main()
{
vector
Ellipse ellipse(1, 2);
Circle circle(13);
EquilateralTriangle equilateralTriangle(13);
IsoscelesTriangle isoscelesTriangle(13, 27);
Trapezoid trapezoid(5, 4, 3);
Kite kite(13, 27);
Rectangle rectangle(1, 2);
Square square(2);
Cone cone(6, 13);
Pyramid pyramid(1, 2, 3);
Cube cube(13);
Cylinder cylinder(13, 27);
Sphere sphere(13);
shapes.push_back(&ellipse);
shapes.push_back(&circle);
shapes.push_back(&equilateralTriangle);
shapes.push_back(&isoscelesTriangle);
shapes.push_back(&trapezoid);
shapes.push_back(&kite);
shapes.push_back(&rectangle);
shapes.push_back(&square);
shapes.push_back(&cone);
shapes.push_back(&pyramid);
shapes.push_back(&cube);
shapes.push_back(&cylinder);
shapes.push_back(&sphere);
...
}
Por fim, itere pelo vetor usando o tipo automático. Para cada objeto, verifique se o objeto é bidimensional ou tridimensional usando o valor de retorno da conversão dinâmica dos objetos da seguinte maneira:
int main()
{
...
for (auto & shape : shapes)
{
if (dynamic_castTwoDimensionalShape*>(shape))
{
auto* tmp = (TwoDimensionalShape*)shape;
cout two-dimensional shape" endl
getArea() endl;
}
else
{
auto* tmp = (ThreeDimensionalShape*)shape;
cout three-dimensional shape" endl
area: " getArea()
endl
getVolume()
endl;
}
cout endl;
}
}
Resposta
Ver o desenvolvimento!!