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)