C++ Tutorial/Class/virtual function

Материал из C\C++ эксперт
Перейти к: навигация, поиск

Access base class"s virtual if derived class does not redefine it

#include <iostream> 
using namespace std; 
 
class BaseClass { 
public: 
  virtual void who() { 
    cout << "Base\n"; 
  } 
}; 
 
class DerivedClass1 : public BaseClass { 
public: 
  void who() { 
    cout << "First derivation\n"; 
  } 
}; 
 
class DerivedClass2 : public BaseClass { 
// who() not defined 
}; 
 
int main() 
{ 
  BaseClass base_obj; 
  BaseClass *p; 
  DerivedClass1 DerivedClass1_obj; 
  DerivedClass2 DerivedClass2_obj; 
 
  p = &base_obj; 
  p->who();  // access BaseClass"s who() 
 
  p = &DerivedClass1_obj; 
  p->who(); // access DerivedClass1"s who() 
 
  p = &DerivedClass2_obj; 
  p->who(); /* access BaseClass"s who() because 
               DerivedClass2 does not redefine it */ 
 
  return 0; 
}
Base
First derivation
Base

A pure virtual function

#include <iostream> 
#include <cstring> 
using namespace std; 
 
class Shape { 
  double width; 
  double height; 
 
  char name[20]; 
public: 
 
  Shape() { 
    width = height = 0.0; 
    strcpy(name, "unknown"); 
  } 
 
  Shape(double w, double h, char *n) { 
    width = w; 
    height = h; 
    strcpy(name, n); 
  } 
 
  Shape(double x, char *n) { 
    width = height = x; 
    strcpy(name, n); 
  } 
 
  void display() { 
    cout << "Width and height are " << width << " and " << height << "\n"; 
  } 
 
  double getWidth() { return width; } 
  double getHeight() { return height; } 
  void setWidth(double w) { width = w; } 
  void setHeight(double h) { height = h; } 
  char *getName() { return name; } 
 
  virtual double area() = 0; 
 
}; 
 
class Triangle : public Shape { 
  char style[20];
public: 
 
  Triangle() { 
    strcpy(style, "unknown"); 
  } 
 
  Triangle(char *str, double w, double h) : Shape(w, h, "triangle") { 
    strcpy(style, str); 
  } 
   
  Triangle(double x) : Shape(x, "triangle") { 
    strcpy(style, "isosceles");  
  } 
 
  double area() { 
    return getWidth() * getHeight() / 2; 
  } 
 
  void showStyle() { 
    cout << "Triangle is " << style << "\n"; 
  } 
}; 
 
class Rectangle : public Shape { 
public: 
 
  Rectangle(double w, double h) : Shape(w, h, "rectangle") { }  
  
  Rectangle(double x) : Shape(x, "rectangle") { }  
 
  bool isSquare() { 
    if(getWidth() == getHeight()) 
       return true; 
    return false; 
  } 
 
  double area() { 
    return getWidth() * getHeight(); 
  } 
}; 
 
int main() { 
  Shape *shapes[4]; 
  
  shapes[0] = &Triangle("right", 8.0, 12.0);  
  shapes[1] = &Rectangle(10);  
  shapes[2] = &Rectangle(10, 4);  
  shapes[3] = &Triangle(7.0);  
  
  for(int i=0; i < 4; i++) {  
    cout << "object is " << shapes[i]->getName() << "\n";  
    cout << "Area is " << shapes[i]->area() << "\n\n";  
  }  
 
  return 0; 
}
object is triangle
Area is 24.5
object is triangle
Area is 24.5
object is triangle
Area is 24.5
object is triangle
Area is 24.5

A virtual function

#include <iostream> 
using namespace std; 
 
class BaseClass { 
public: 
  virtual void who() { // specify a virtual function 
    cout << "Base\n"; 
  } 
}; 
 
class DerivedClass1 : public BaseClass { 
public: 
  void who() { // redefine who() for DerivedClass1  
    cout << "First derivation\n"; 
  } 
}; 
 
class DerivedClass2 : public BaseClass { 
public: 
  void who() { // redefine who() for DerivedClass2 
    cout << "Second derivation\n"; 
  } 
}; 
 
int main() 
{ 
  BaseClass base_obj; 
  BaseClass *p; 
  DerivedClass1 DerivedClass1_obj; 
  DerivedClass2 DerivedClass2_obj; 
 
  p = &base_obj; 
  p->who();  // access BaseClass"s who 
 
  p = &DerivedClass1_obj; 
  p->who(); // access DerivedClass1"s who 
 
  p = &DerivedClass2_obj; 
  p->who();  // access DerivedClass2"s who 
   
  return 0; 
}
Base
First derivation
Second derivation

Class with only virtual methods

#include <iostream>
 
 class Shape
 {
 public:
     Shape(){}
     virtual ~Shape(){}
     virtual long GetArea() = 0; 
     virtual long GetPerim()= 0;
     virtual void Draw() = 0;
 };
 
 class Circle : public Shape
 {
 public:
     Circle(int radius):itsRadius(radius){}
     ~Circle(){}
     long GetArea() { return 3 * itsRadius * itsRadius; }
     long GetPerim() { return 9 * itsRadius; }
     void Draw();
 private:
     int itsRadius;
     int itsCircumference;
 };
 
 void Circle::Draw()
 {
     std::cout << "Circle drawing \n";
 }
 
 
 class Rectangle : public Shape
 {
 public:
     Rectangle(int len, int width):
         itsLength(len), itsWidth(width){}
     virtual ~Rectangle(){}
     virtual long GetArea() { return itsLength * itsWidth; }
     virtual long GetPerim() {return 2*itsLength + 2*itsWidth; }
     virtual int GetLength() { return itsLength; }
     virtual int GetWidth() { return itsWidth; }
     virtual void Draw();
 private:
     int itsWidth;
     int itsLength;
 };
 
 void Rectangle::Draw()
 {
     for (int i = 0; i<itsLength; i++)
     {
         for (int j = 0; j<itsWidth; 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 len):Rectangle(len,len) {}
 
 Square::Square(int len, int width):Rectangle(len,width)
 {
     if (GetLength() != GetWidth())
         std::cout << "Error, not a square... a Rectangle??\n";
 }
 
 int main()
 {
     Shape * sp;
 
     sp = new Circle(5);
     sp->Draw();
     
     sp = new Rectangle(4,6);
     sp->Draw();
     
     sp = new Square(5);
     sp->Draw();
     return 0;
 }
Circle drawing
x x x x x x
x x x x x x
x x x x x x
x x x x x x
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x

Implementing pure virtual functions

#include <iostream>
 
 class Shape
 {
 public:
     Shape(){}
     virtual ~Shape(){}
     virtual long GetArea() = 0; 
     virtual long GetPerim()= 0;
     virtual void Draw() = 0;
 private:
 };
 
 void Shape::Draw()
 {
     std::cout << "Abstract drawing mechanism!\n";
 }
 
 class Circle : public Shape
 {
 public:
     Circle(int radius):itsRadius(radius){}
     ~Circle(){}
     long GetArea() { return 3 * itsRadius * itsRadius; }
     long GetPerim() { return 9 * itsRadius; }
     void Draw();
 private:
     int itsRadius;
     int itsCircumference;
 };
 
 void Circle::Draw()
 {
     std::cout << "Circle drawing routine here!\n";
     Shape::Draw();
 }
 
 class Rectangle : public Shape
 {
 public:
     Rectangle(int len, int width):
         itsLength(len), itsWidth(width){}
     virtual ~Rectangle(){}
     long GetArea() { return itsLength * itsWidth; }
     long GetPerim() {return 2*itsLength + 2*itsWidth; }
     virtual int GetLength() { return itsLength; }
     virtual int GetWidth() { return itsWidth; }
     void Draw();
 private:
     int itsWidth;
     int itsLength;
 };
 
 void Rectangle::Draw()
 {
     for (int i = 0; i<itsLength; i++)
     {
         for (int j = 0; j<itsWidth; j++)
             std::cout << "x ";
 
         std::cout << "\n";
     }
     Shape::Draw();
 }
 
 class Square : public Rectangle
 {
 public:
     Square(int len);
     Square(int len, int width);
     ~Square(){}
     long GetPerim() {return 4 * GetLength();}
 };
 
 Square::Square(int len):Rectangle(len,len)
 {}
 
 Square::Square(int len, int width):Rectangle(len,width){
     if (GetLength() != GetWidth())
         std::cout << "Error, not a square... a Rectangle??\n";
 }
 
 int main()
 {
     Shape * sp;
 
     sp = new Circle(5);
     sp->Draw();
     sp = new Rectangle(4,6);
     sp->Draw();
     sp = new Square (5);
     sp->Draw();
     return 0;
 }
Circle drawing routine here!
Abstract drawing mechanism!
x x x x x x
x x x x x x
x x x x x x
x x x x x x
Abstract drawing mechanism!
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x
Abstract drawing mechanism!

Multiple virtual member functions called in turn

#include <iostream>
 
 class Animal
 {
 public:
     Animal():itsAge(1) {  }
     ~Animal() { }
     virtual void Speak() const { std::cout << "Animal speak!\n"; }
 protected:
     int itsAge;
 };
 
 class Dog : public Animal
 {
 public:
     void Speak()const { std::cout << "Woof!\n"; }
 };
 
 
 class Cat : public Animal
 {
 public:
     void Speak()const { std::cout << "Meow!\n"; }
 };
 
 
 class Horse : public Animal
 {
 public:
     void Speak()const { std::cout << "Winnie!\n"; }
 };
 
 class Pig : public Animal
 {
 public:
     void Speak()const { std::cout << "Oink!\n"; }
 };
 
 int main()
 {
     Animal* theArray[5];
     Animal* ptr;
     int i;
     theArray[0] = new Dog;
     theArray[1] = new Cat;
     theArray[2] = new Horse;
     theArray[3] = new Pig;
     theArray[4] = new Animal;
     
     for (i=0;i<5;i++)
         theArray[i]->Speak();
     return 0;
 }
Woof!
Meow!
Winnie!
Oink!
Animal speak!

Use Virtual Functions to change the method behaviour

#include <iostream>  
using namespace std;
class Base {  
public:  
  virtual void who(void) {
    cout << "Base\n";  
  }  
};  
     
class first_d : public Base {  
public:  
  void who(void) { // define who() relative to first_d  
    cout << "First derivation\n";  
  }  
};  
     
class second_d : public Base {  
public:  
  void who(void) { // define who() relative to second_d  
    cout << "Second derivation\n";  
  }  
};  
     
int main(void)  
{  
  Base base_obj;  
  Base *p;  
  first_d first_obj;  
  second_d second_obj;  
     
  p = &base_obj;  
  p->who();  // access Base"s who  
     
  p = &first_obj;  
  p->who(); // access first_d"s who  
     
  p = &second_obj;  
  p->who();  // access second_d"s who  
     
  return 0;  
}

Use virtual function to calculate area for different shapes

#include <iostream>  
  using namespace std;
  class Shape {  
  protected:  
    double x, y;  
  public:  
    void set_dim(double i, double j=0) {  
      x = i;  
      y = j;  
    }  
    virtual void show_area(void) {  
      cout << "No area computation defined ";  
      cout << "for this class.\n";  
    }  
  } ;  
       
  class triangle : public Shape {  
    public:  
      void show_area(void) {  
        cout << "Triangle with height ";  
        cout << x << " and base " << y;  
        cout << " has an area of ";  
        cout << x * 0.5 * y << ".\n";  
      }  
  };  
       
  class square : public Shape {  
    public:  
      void show_area(void) {  
        cout << "Square with dimensions ";  
        cout << x << "x" << y;  
        cout << " has an area of ";  
        cout << x *  y << ".\n";  
       }  
  };  
       
  class circle : public Shape {  
    public:  
      void show_area(void) {  
        cout << "Circle with radius ";  
        cout << x;  
        cout << " has an area of ";  
        cout << 3.14 * x * x;  
      }  
  } ;  
       
  main(void)  
  {  
    Shape *p;  
    triangle t; 
    square s;  
    circle c;  
       
    p = &t;  
    p->set_dim(10.0, 5.0);  
    p->show_area();  
       
    p = &s;  
    p->set_dim(10.0, 5.0);  
    p->show_area();  
       
    p = &c;  
    p->set_dim(9.0);  
    p->show_area();  
       
    return 0;  
  }

Why Virtual Functions: one interface, multiple methods

#include <iostream>  
    using namespace std;       
  class Shape {  
  protected:  
    double x, y;  
  public:  
    void set_dim(double i, double j) {  
      x = i;  
      y = j;  
    }  
    virtual void show_area(void) {  
      cout << "No area computation defined ";  
      cout << "for this class.\n";  
    }  
  } ;  
       
  class triangle : public Shape {  
    public:  
      void show_area(void) {  
        cout << "Triangle with height ";  
        cout << x << " and base " << y;  
        cout << " has an area of ";  
        cout << x * 0.5 * y << ".\n";  
      }  
  };  
       
  class square : public Shape {  
    public:  
      void show_area(void) {  
        cout << "Square with dimensions ";  
        cout << x << "x" << y;  
        cout << " has an area of ";  
        cout << x *  y << ".\n";  
      }  
  };  
       
  main(void)  
  {  
    Shape *p;  
       
    triangle t; 
    square s;  
       
    p = &t;  
    p->set_dim(10.0, 5.0);  
    p->show_area();  
    p = &s;  
    p->set_dim(10.0, 5.0);  
    p->show_area();  
       
    return 0;  
  }