Pure Virtual Functions and Abstraction

I'm having an issue creating a concrete class using polymorphism. I've declared a pure virtual area() function in two different classes and one pure virtual volume() function in one of these classes. In their derivative classes, I have overridden these functions but my compiler is telling me that the derivative classes are abstract and can not be instantiated. Any ideas why? I'm sure it's something simple that I'm overlooking. Thanks for your help, Adam.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef SHAPE_H
#define SHAPE_H

#include <iostream>
using std::ostream;

class Shape 
{
   friend ostream & operator<<( ostream &, Shape & );
public:
   Shape( double = 0.0, double = 0.0 );
   double getCenterX() const;
   double getCenterY() const;

   //Write virtual pure print function
   virtual void print() const = 0;

protected:
   double xCenter;
   double yCenter;
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "Shape.h"

Shape::Shape( double x, double y )
{
   xCenter = x;
   yCenter = y;
}

double Shape::getCenterX() const 
{ 
    return xCenter; 
}

double Shape::getCenterY() const 
{ 
    return yCenter; 
}

ostream & operator<<( ostream &out, Shape &s )
{
   s.print();
   return out;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef TWODIM_H
#define TWODIM_H

#include "Shape.h"

class TwoDimensionalShape : public Shape 
{
public:

    // Write the constructor for 2-dimensional shape 
    TwoDimensionalShape( double = 0.0, double = 0.0 );

    // declare pure virtual member functions area
    virtual double area( double ) const = 0;

};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef THREEDIM_H
#define THREEDIM_H

#include "Shape.h"

class ThreeDimensionalShape : public Shape 
{
public:

    // Write the constructor for 3-dimensional shape 
    ThreeDimensionalShape( double = 0.0, double = 0.0 );
    
    // declare a pure virtual member function area
    virtual double area( double ) const = 0;

    // declare a pure virtual member function volume
    virtual double volume( double ) const = 0;

};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef SQUARE_H
#define SQUARE_H

#include "TwoDimensionalShape.h"

// write statement for square public inheritance from 2-dimensional class
class Square : public TwoDimensionalShape 
{    
public:
   Square( double = 0.0, double = 0.0, double = 0.0 );
   double getSideLength() const;
   virtual double area() const;
   virtual void print() const;
private:
   double sideLength;
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "Square.h"

#include <iostream>
using std::cout;

Square::Square( double s, double x, double y )
   : TwoDimensionalShape( x, y ) 
{ 
    sideLength = s > 0 ? s : 0; 
}

double Square::getSideLength() const 
{ 
    return sideLength; 
}

double Square::area() const 
{
    // write the code for calculating the area of a square
    return sideLength * sideLength;
}

void Square::print() const
{
   cout << "Square with side length " << sideLength << "; center at ("
        << xCenter << ", " << yCenter << ");\narea of " << area() << '\n';
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef CUBE_H
#define CUBE_H

#include "ThreeDimensionalShape.h"
// write statements for Cube to publicly inherit from 3-dimensional class 
class Cube : public ThreeDimensionalShape 
{ 
public:
   Cube( double = 0.0, double = 0.0, double = 0.0 );
   virtual double area() const;
   virtual double volume() const;
   double getSideLength() const;
   virtual void print() const;

private:
   double sideLength;
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "Cube.h"

#include <iostream>
using std::cout;

//Write the constructor for Cube class
Cube::Cube( double s, double x, double y )
:ThreeDimensionalShape( x, y )
{
    sideLength = s > 0 ? s : 0;
}

double Cube::area() const 
{ 
    return 6 * sideLength * sideLength; 
}

double Cube::volume() const
{ 
    return sideLength * sideLength * sideLength; 
}

double Cube::getSideLength() const 
{ 
    return sideLength; 
}

void Cube::print() const
{
   cout << "Cube with side length " << sideLength << "; center at ("
        << xCenter << ", " << yCenter << ");\narea of "
        << area() << "; volume of " << volume() << '\n';
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream> 

using std::cout; 
using std::endl; 
using std::cin; 
using std::ios;

#include "Square.h"
#include "Cube.h"

int main()
{
   Square sqr( 12, 2, 2 );
   Cube cub( 2.2 );
   Shape *ptr[ 2 ] = { &sqr, &cub };

   for ( int x = 0; x < 2; ++x )
      cout << *( ptr[ x ] ) << '\n';

   return 0;
}


Following is just a guess.

A derived class must give some implementation (can be virtual) of all pure virtual functions of the base class. In your case, class Shape has a pure virtual function print() which is not implemented in the derived classes TwoDinensionalShape and ThreeDimensionalShape. To me, this raises a red flag.
Your TwoDimensionalShape::area() function takes a double as an argument. But the one in Square does not. This means that it is not implementing the pure virtual function. Functions with different parameters are considered different functions in C++. So you can not implement a pure virtual function with a different function of the same name. It MUST have the same parameter specifications.
Thanks for the reply, but a derived class must only give some implementation if it is to be concrete. The TwoDimensionalShape and ThreeDimensionalShape classes are abstract, not concrete.
The derived class MUST implement EXACTLY what the abstract parent class says it should implement. If the parent class specifies a pure virtual function then the derived class MUST implement it if it wants to be able to be instantiated.
Galik, Thank you very much. I knew it was something simple. I've corrected the pure virtual functions and my Cube classes and Square classes can now be instantiated.

Now, I'm getting some different errors.

1
2
3
4
Square.obj : error LNK2028: unresolved token (0A000297) "public: __thiscall TwoDimensionalShape::TwoDimensionalShape(double,double)" (??0TwoDimensionalShape@@$$FQAE@NN@Z) referenced in function "public: __thiscall Square::Square(double,double,double)" (??0Square@@$$FQAE@NNN@Z)
1>Cube.obj : error LNK2028: unresolved token (0A000279) "public: __thiscall ThreeDimensionalShape::ThreeDimensionalShape(double,double)" (??0ThreeDimensionalShape@@$$FQAE@NN@Z) referenced in function "public: __thiscall Cube::Cube(double,double,double)" (??0Cube@@$$FQAE@NNN@Z)
1>Square.obj : error LNK2019: unresolved external symbol "public: __thiscall TwoDimensionalShape::TwoDimensionalShape(double,double)" (??0TwoDimensionalShape@@$$FQAE@NN@Z) referenced in function "public: __thiscall Square::Square(double,double,double)" (??0Square@@$$FQAE@NNN@Z)
1>Cube.obj : error LNK2019: unresolved external symbol "public: __thiscall ThreeDimensionalShape::ThreeDimensionalShape(double,double)" (??0ThreeDimensionalShape@@$$FQAE@NN@Z) referenced in function "public: __thiscall Cube::Cube(double,double,double)" (??0Cube@@$$FQAE@NNN@Z)


This is certainly good to know. I do not have too much experience with using virtual functions beyond the simple base->derived.
You need to provide a constructor implementation for your TwoDimensionalShape and ThreeDimensionalShape classes.
Galik, That's interesting. I was thinking the same thing, but a .cpp file was not provided to complete this problem. I'll give it a shot now. Thanks.
Galik, thank you so much! That was it. Problem solved...
Topic archived. No new replies allowed.