崔毅东 C++程序设计入门(上) 第6单元:丹枫虽老犹多态–继承与多态 笔记

在这里插入图片描述在这里插入图片描述在这里插入图片描述
GeometricObject.h

#ifndef GEOMETRICOBJECT_H
#define GEOMETRICOBJECT_H
#include <string>
using namespace std;

class GeometricObject
{
  public:
    GeometricObject();
    GeometricObject(string color, bool filled);
    string getColor();
    void setColor(string color);
    bool isFilled();
    void setFilled(bool filled);
    string toString();

  private:
    string color_;
    bool filled_;
}; // Must place semicolon here

#endif

GeometricObject.cpp

#include "GeometricObject.h"

GeometricObject::GeometricObject()
{
  color_ = "white";
  filled_ = false;
}

GeometricObject::GeometricObject(string color, bool filled)
{
  color_ = color;
  filled_ = filled;
}

string GeometricObject::getColor()
{
  return color_;
}

void GeometricObject::setColor(string color)
{
  color_ = color;
}

bool GeometricObject::isFilled()
{
  return filled_;
}

void GeometricObject::setFilled(bool filled)
{
  filled_ = filled;
}

string GeometricObject::toString()
{
  return "Geometric object | color: " + color_ +
         " | filled: " + ((filled_) ? "true" : "false");
}

DerivedCircle.h

#ifndef DERIVEDCIRCLE_H
#define DERIVEDCIRCLE_H
#include "GeometricObject.h"

class Circle: public GeometricObject
{
public:
  Circle();
  Circle(double);
  Circle(double radius, string color, bool filled);
  double getRadius();
  void setRadius(double);
  double getArea();
  double getPerimeter();
  double getDiameter();

private:
  double radius_;
};  // Must place semicolon here

#endif

DerivedCircle.cpp

#include "DerivedCircle.h"

// Construct a default circle object
Circle::Circle()
{
  radius_ = 1;
}

// Construct a circle object with specified radius
Circle::Circle(double radius)
{
  radius_ = radius;
}

// Return the radius of this circle
double Circle::getRadius()
{
  return radius_;
}

// Set a new radius
void Circle::setRadius(double radius)
{
  radius_ = (radius >= 0) ? radius : 0;
}

// Return the area of this circle
double Circle::getArea()
{
  return radius_ * radius_ * 3.14159;
}

// Return the perimeter of this circle
double Circle::getPerimeter()
{
  return 2 * radius_ * 3.14159;
}

// Return the diameter of this circle
double Circle::getDiameter()
{
  return 2 * radius_;
}

Rectangle.h

#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "GeometricObject.h"

class Rectangle: public GeometricObject
{
public:
  Rectangle();
  Rectangle(double width, double height);
  Rectangle(double width, double height, string color, bool filled);
  double getWidth();
  void setWidth(double);
  double getHeight();
  void setHeight(double);
  double getArea();
  double getPerimeter();

private:
  double width_;
  double height_;
};  // Must place semicolon here

#endif

Rectangle.cpp

#include "Rectangle.h"

// Construct a default retangle object
Rectangle::Rectangle()
{
  width_ = 1;
  height_ = 1;
}

// Construct a rectangle object with specified width and height
Rectangle::Rectangle(double width, double height)
{
  width_ = width;
  height_ = height;
}

// Return the width of this rectangle
double Rectangle::getWidth()
{
  return width_;
}

// Set a new radius
void Rectangle::setWidth(double width)
{
  width_ = (width >= 0) ? width : 0;
}

// Return the height of this rectangle
double Rectangle::getHeight()
{
  return height_;
}

// Set a new height
void Rectangle::setHeight(double height)
{
  height_ = (height >= 0) ? height : 0;
}

// Return the area of this rectangle
double Rectangle::getArea()
{
  return width_ * height_;
}

// Return the perimeter of this rectangle
double Rectangle::getPerimeter()
{
  return 2 * (width_ + height_);
}

TestGeometricObject.cpp

#include "GeometricObject.h"
#include "DerivedCircle.h"
#include "Rectangle.h"
#include <iostream>
using namespace std;

int main()
{
  GeometricObject shape;
  shape.setColor("red");
  shape.setFilled(true);
  cout << shape.toString() << endl << endl;

  Circle circle(5);
  circle.setColor("black");
  circle.setFilled(false);
  cout << circle.toString() << endl;
  cout << "  Circle radius: " << circle.getRadius() <<
          " area: "         << circle.getArea() <<
          " perimeter: "    << circle.getPerimeter() <<
          " \n" << endl;


  Rectangle rectangle(2, 3);
  rectangle.setColor("orange");
  rectangle.setFilled(true);
  cout << rectangle.toString() << endl;
  cout << "  Rectangle width: " << rectangle.getWidth() <<
          " height: "         << rectangle.getHeight() <<
          " area: "           << rectangle.getArea() <<
          " perimeter: "      << rectangle.getPerimeter() <<
          " \n" << endl;

  return 0;
}

第02节:构造函数和析构函数

在这里插入图片描述
右图是C++11标准的新特性
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
ChainingDemo.cpp

#include <iostream>
using namespace std;

// Person <-- Employee <-- Faculty
class Person
{
public:
  Person()
  {
    cout << "Person's constructor is invoked" << endl;
  }

  ~Person()
  {
    cout << "Person's destructor is invoked" << endl;
  }
};

class Employee: public Person
{
public:
  Employee()
  {
    cout << "Employee's constructor is invoked" << endl;
  }

  ~Employee()
  {
    cout << "Employee's destructor is invoked" << endl;
  }
};

class Faculty: public Employee
{
public:
  Faculty()
  {
    cout << "Faculty's constructor is invoked" << endl;
  }

  ~Faculty()
  {
    cout << "Faculty's destructor is invoked" << endl;
  }
};

int main()
{
  Faculty faculty;
  return 0;
}

在这里插入图片描述在这里插入图片描述
派生类会调用基类的无参构造函数,而基类只有有参构造函数时会报错
解决方法:基类加无参构造函数
派生类构造函数加初始化列表
Apple::Apple() :Fruit(1){
}

第03节:函数重定义

在这里插入图片描述在这里插入图片描述在这里插入图片描述U06S03 - C++中子类是否可以重载父类的方法?
如下代码的输出结果是什么?

#include <iostream>
using namespace std;
class B{ 
public: 
  int f(int i) { 
    cout << "f(int): "; 
    return i+1;
  } 
  // ... 
};
 
class D : public B {
public:
  double f(double d) { 
    cout << "f(double): ";
    return d+1.3;
  } 
  // ...
};
 
int main(){ 
  D* pd = new D;
  cout << pd->f(2) << '\n';
  cout << pd->f(2.3) << '\n';
}

C++ 中是否有跨域重载: 在派生类中重载基类的函数?

怎么才能使得上面的例子中类D的函数可以重载类B的函数呢?
答:看样子,好象不能。加类名可以,int main(){
D* pd = new D;
cout << pd->B::f(2) << ‘\n’;
cout << pd->f(2.3) << ‘\n’;
}

第04节:多态和虚函数

在这里插入图片描述
在这里插入图片描述在这里插入图片描述WhyPolymorphismDemo.cpp

#include <iostream>
using namespace std;

class C
{
public:
  string toString()
  {
    return "class C";
  }
};

class B: public C
{
  string toString()
  {
    return "class B";
  }
};

class A: public B
{
  string toString()
  {
    return "class A";
  }
};

void displayObject(C x)
{
  cout << x.toString().data() << endl;
}

int main()
{
  displayObject(A());
  displayObject(B());
  displayObject(C());
  return 0;
}

在这里插入图片描述在这里插入图片描述PolymorphismDemo.cpp

#include <iostream>
using namespace std;

class C
{
public:
  virtual string toString()
  {
    return "class C";
  }
};

class B: public C
{
  string toString()
  {
    return "class B";
  }
};

class A: public B
{
  string toString()
  {
    return "class A";
  }
};

void displayObject(C *p)
{
  cout << p->toString().data() << endl;
}

int main()
{
  A a = A();
  B b = B();
  C c = C();
  displayObject(&a);
  displayObject(&b);
  displayObject(&c);
  return 0;
}

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
U06S04 - 你知道虚函数表吗?
虚函数表 是C++编译器实现运行时多态的一种方法。你能查查资料,说说 当一个虚函数被调用时, 程序是如何通过虚函数表找到对应的函数的?
答:当声明类时,每声明一个虚函数,编译器会自动在虚函数表中存入此函数的入口地址

当在派生类中重写此函数时,相应的虚函数表中的地址会变为重写后的函数的入口地址。
C++ 虚函数表解析

第05节:访问控制 (可见性控制)

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

第06节:抽象类与纯虚函数

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
AbstractGeometricObject.h

#ifndef ABSTRACTGEOMETRICOBJECT_H
#define ABSTRACTGEOMETRICOBJECT_H
#include <string>
using namespace std;

class GeometricObject
{
public:
  GeometricObject();
  GeometricObject(string color, bool filled);

public:
  string getColor();
  void setColor(string color);
  bool isFilled();
  void setFilled(bool filled);
  string toString();
  //virtual double getArea() {  };
  //virtual double getPerimeter() {  };
  virtual double getArea() = 0;
  virtual double getPerimeter() = 0;

private:
  string color_;
  bool filled_;
}; // Must place semicolon here

#endif
GeometricObject geometricObject;

会报错,抽象类不能实例化
在这里插入图片描述
改成下面代码即可

virtual double getArea() {  };
  virtual double getPerimeter() {  };

U06S06 - 纯虚函数的作用
纯虚函数没有函数体,所以,写纯虚函数的程序员都是懒蛋, 对吗?

纯虚函数是让程序员变懒的一种办法,还是另有妙用? 视频中并没有做过多解释,你能说说自己的看法吗?

答:我最原始的理解:纯虚函数就是在父类中起个名字,来说明子类中共同需要的功能,但由于子类的多态特性,差别很大,几乎没有共同的行为模式。具体的实现留给了子类。

(by bjbest)

第07节:动态类型转换

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/dldldl1994/article/details/86768472