#include <iostream>

class Shape
{
public:
Shape() {}
virtual ~Shape() {}
virtual long getArea() { return -1; } // error
virtual long getPerim() { return -1; }
virtual void draw() {}
};

class Circle : public Shape
{
public:
Circle(int newRadius):radius(newRadius) {}
~Circle() {}
long getArea() { return 3 * radius * radius; }
long getPerim() { return 9 * radius; }
void draw();
private:
int radius;
int circumference;
};

void Circle::draw()
{
std::cout << "Circle drawing routine here!\n";
}

class Rectangle : public Shape
{
public:
Rectangle(int newLen, int newWidth):
length(newLen), width(newWidth) {}
virtual ~Rectangle() {}
virtual long getArea() { return length * width; }
virtual long getPerim() { return 2 * length + 2 * width; }
virtual int getLength() { return length; }
virtual int getWidth() { return width; }
virtual void draw();
private:
int width;
int length;
};

void Rectangle::draw()
{
for (int i = 0; i < length; i++)
{
for (int j = 0; j < width; j++)
std::cout << "x ";

std::cout << "\n";
}
}

class Square : public Rectangle
{
public:
Square(int len);
Square(int len, int width);
~Square() {}
long getPerim() { return 4 * getLength(); }
};

Square::Square(int newLen):
Rectangle(newLen, newLen)
{}

Square::Square(int newLen, int newWidth):
Rectangle(newLen, newWidth)
{
if (getLength() != getWidth())
std::cout << "Error, not a square ... a rectangle?\n";
}

int main()
{
int choice;
bool fQuit = false;
Shape * sp;

while (1)
{
std::cout << "(1) Circle (2) Rectangle (3) Square (0) Quit: ";
std::cin >> choice;

switch (choice)
{
case 1:
sp = new Circle(5);
break;
case 2:
sp = new Rectangle(4, 6);
break;
case 3:
sp = new Square(5);
break;
default:
fQuit = true;
break;
}
if (fQuit)
break;

sp->draw();
std::cout << "\n";
}
return 0;
}

shape是一种抽象数据类型(ADT),只为其派生类提供接口,如果试图实例化Shape对象,将很麻烦,也许应该使其不可能。

抽象数据类型表示一种概念(如形状),而不是具体的对象(如圆)。在c++中,ADT只能用于其他类的基类,而不能创建其实,因此,如果将Shape声明为ADT就无法创建Shape实例了。

18.2纯虚函数

C++通过提供纯虚函数来支持创建抽象数据类型。纯虚函数是必须在派生类中重写的虚函数。通过将虚函数初始化为 0 来将其声明为纯虚的。

任何包含一个或多个纯虚函数的类都是ADT不能将其实例化,试图这样做将导致编译错误,将纯虚函数放在类中向其客户指出以下两点。

1.不要创建这个类的对象,应该使其派生。

2.务必重写这个类继承的纯虚函数。

在ADT派生而来的类中,继承的纯虚函数仍然是纯虚的,要实例化的话,必须要对派生类中每个纯虚函数,否则派生类也将是ADT。

ADT不能实例化如下:

#include <iostream>
using namespace std;

class Shape
{
public:
Shape() {}
virtual ~Shape() {}
virtual long getArea() { return -1; } // error
//virtual long getArea()=0;


virtual long getPerim() { return -1; }
//virtual long getPerim()=0;



virtual void draw() {}
//virtual void draw()=0;


};

class Circle : public Shape
{
public:
Circle(int newRadius):radius(newRadius) {cout<<"circle"<<endl;}
~Circle() {}
long getArea() { return 3 * radius * radius; }
long getPerim() { return 9 * radius; }
void draw();
private:
int radius;
int circumference;
};

void Circle::draw()
{
std::cout << "Circle drawing routine here!\n";
}

class Rectangle : public Shape
{
public:
Rectangle(int newLen, int newWidth):
length(newLen), width(newWidth) {}
virtual ~Rectangle() {}
virtual long getArea() { return length * width; }
virtual long getPerim() { return 2 * length + 2 * width; }
virtual int getLength() { return length; }
virtual int getWidth() { return width; }
virtual void draw();
private:
int width;
int length;
};

void Rectangle::draw()
{
for (int i = 0; i < length; i++)
{
for (int j = 0; j < width; j++)
std::cout << "x ";

std::cout << "\n";
}
}

class Square : public Rectangle
{
public:
Square(int len);
Square(int len, int width);
~Square() {}
long getPerim() { return 4 * getLength(); }
};

Square::Square(int newLen):
Rectangle(newLen, newLen)
{}

Square::Square(int newLen, int newWidth):
Rectangle(newLen, newWidth)
{
if (getLength() != getWidth())
std::cout << "Error, not a square ... a rectangle?\n";
}

int main()
{
int choice;
bool fQuit = false;
Shape * sp;

// Shape *ptr=new Shape; //ci chu shi bu neng chuang jian shape dui xiang de

while (1)
{
std::cout << "(1) Circle (2) Rectangle (3) Square (0) Quit: ";
std::cin >> choice;

switch (choice)
{
case 1:
sp = new Circle(5);
break;
case 2:
sp = new Rectangle(4, 6);
break;
case 3:
sp = new Square(5);
break;
default:
fQuit = true;
break;
}
if (fQuit)
break;

sp->draw();
std::cout << "\n";
}
return 0;
}