1, Inheritance access test
Design member functions or variables of class A with different attributes such as public, protected and private;
Class B inherits A through public, protected, private and other ways, and tests the member function or variable accessing A in the member function of class B;
Add member functions or variables with different attributes such as public, protected and private to class B, and test and access each member function or variable of B externally;
B inherits A in A private way and tries to promote some public members in A to public.
// Base class Person class Person { public: Person(); string m_strName; protected: string m_strSex; private: int m_nAge; }; // Test Person void TestPerson();
Person::Person() { // Member functions can access all variables in the class m_strName = ""; m_strSex = "boy"; m_nAge = 18; } void TestPerson() { Person perObj; //Public members modified by public keyword can be accessed externally perObj.m_strName = "Luoxiaobin"; //protected and private decorated members cannot be accessed externally //perObj.m_strSex = "B"; //perObj.m_nAge = 18; }
1.public inheritance
class Student: public Person { public: void SetSex(string strSex="") { m_strName = ""; m_strSex = strSex; // You can access the public and protected member variables in the base class // m_nAge = 0;// Cannot access // Inside the member function of an inherited class, you can only access the public and protected properties of the parent class } // inline string GetSex();// Explicit inline function string GetSex()//Implicit inline function { Person::SetSex();//Call the SexSex() function of the parent class Person SetSex("");//Call the SexSex() function of the subclass Student return m_strSex; } };
Student stuObj; string strSex = stuObj.GetSex();// The GetSex() function must be placed in the header file, or there will be a compilation error stuObj.m_strName = "LuoXiaobin";
2.protected inheritance
class Teacher: protected Person { public: void SetSex(string strSex="") { m_strName = ""; m_strSex = strSex; // m_nAge = 0;// Cannot access // Inside the member function of an inherited class, you can only access the public and protected properties of the parent class //Whether the subclass inherits the parent class in public,protected or private, //For subclass member functions, the internal access is unchanged, that is, both public and protected attributes can be accessed, while the external access is different } };
Teacher teacher; teacher.SetSex();// After inheritance, SetSex() is a protected property, which cannot be accessed externally // When the parent class and itself have SetSex functions with the same name, they call their own internal functions // No matter what kind of attribute the SetSex function of the parent class is, it calls the SetSex function of its Teacher class
3.private inheritance
class Pupil: private Person { public: using Person::m_strName; using Person::m_strSex; // After inheritance through private, m, which was originally public_ Strname becomes private, // Originally protected m_strSex also becomes private, which can be accessed through using promotion // using Person::m_nAge; // Inherited classes can only access the public and private properties of the base class, so they cannot promote m through using_ The attribute of nage accesses it string & GetName() { return m_strName; } void SetSex(string strSex="") { m_strName = ""; m_strSex = strSex; // m_nAge = 0; } };
Pupil pupil; pupil.GetName() = ""; pupil.m_strName = ""; pupil.m_strSex = ""; // pupil.m_nAge = 18;
4. Summary
public, protected and private specify the inheritance method:
Different inheritance methods affect the access rights of base class members in derived classes.
-
public inheritance method
All public members in the base class are public attributes in the derived class;
All protected members in the base class are protected attributes in the derived class;
All private members in a base class cannot be used in a derived class. -
protected inheritance method
All public members in the base class are protected in the derived class;
All protected members in the base class are protected attributes in the derived class;
All private members in a base class cannot be used in a derived class. -
private inheritance method
All public members in the base class are private attributes in the derived class;
All protected members in the base class are private attributes in the derived class;
All private members in a base class cannot be used in a derived class.
Through the above analysis, it can be found that:
-
The access rights of base class members in derived classes must not be higher than those specified in the inheritance method. In other words, public, protected and private in the inheritance method are used to indicate the highest access rights of base class members in derived classes.
-
Regardless of the inheritance method, the private member in the base class cannot be used in the derived class (it cannot be accessed or called in the member function of the derived class).
-
If you want the members of the base class to be inherited by the derived class and used without obstacles, these members can only be declared as public or protected; Only those members that you do not want to use in derived classes are declared private.
-
If you want the members of the base class to be neither exposed (not accessible through objects) nor used in derived classes, you can only declare them protected.
Note that what we say here is that the private members of the base class cannot be used in derived classes, and we do not say that the private members of the base class cannot be inherited. In fact, the private member of the base class can be inherited, and (member variable) will occupy the memory of the derived class object. It is just invisible in the derived class, so it can't be used. This feature of private member can well hide the implementation of base class from derived classes to reflect the encapsulation of object-oriented.
Change access rights:
using can only change the access permissions of public and protected members in the base class, not private members. Because private members in the base class are invisible in derived classes and cannot be used at all, private members in the base class cannot be accessed in derived classes anyway.
2, Friend class inheritance test
1. Three friend methods
class Person { public: Person(); private: int m_nAge; friend class A; // The first way --- friend member function // friend void A::TestFriend(Person & per);// Only give permissions to members of a class // The second way --- friend global function friend void TestFriendFun(Person & per) { per.m_nAge = 10; } // The third way --- friend class friend class Student;//The Studnet class can access all Person member functions // friend class Student::GetAge(); };
2. Friend inheritance test
(1) The friend class cannot be passed: the friend of the base class Person is given to the derived class Student, and the derived class Lecturer inherits the Student class, but Lecture still cannot access the member of Person.
class Person { private: int m_nAge; // The third way --- friend class friend class Student;//The Studnet class can access the private member functions of all persons };
class Lecturer : public Student { public: int GetAge() { // m_nAge = 10; // Error reporting: m_nAge is a private member of the Person class. That is, a friend class cannot be passed m_strName = ""; } };
(2) The friend class cannot access the new member variable of the derived class of the base class
class Person { private: int m_nAge; friend class A;// The base class Person friend gives the entire class A };
class A { public: void TestFriend(Person & per); void TestFriend(Student & per); };
class Student: public Person { private: int m_nNo; }; void A::TestFriend(Student & per) { per.m_nAge = 10;// You can access the private member of the base class Person per.m_nNo = 100;// private members of derived class Student cannot be accessed // m_nNo is a private member of the derived class Student // Similarly, any newly added member variable in a derived class cannot be accessed }
(3) Friend to a specific member of a specific class: only this member can access the members of the base class, and other classes and other members of this class cannot access.
class A { public: void TestFriend(Person & per); void TestFriendA(Person & per); }; // Base class Person class Person { friend void A::TestFriend(Person & per);// Only give permissions to specific members of a class }; void A::TestFriend(Person & per) { per.m_nAge = 10; // Only class A testfriends can access m_nAge } void A::TestFriendA(Person & per) { per.m_nAge = 10; // The member in class A does not have permission to access the member of the base class Person }
3, Comprehensive application of polymorphism
Polymorphism literally means multiple forms. Polymorphism is used when there is a hierarchy between classes and classes are associated through inheritance.
C + + polymorphism means that when calling member functions, different functions will be executed according to the type of object calling the function.
1. General polymorphism function
#include <iostream> using namespace std; class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } int area() { cout << "Parent class area :" <<endl; return 0; } }; class Rectangle: public Shape{ public: Rectangle( int a=0, int b=0):Shape(a, b) { } int area () { cout << "Rectangle class area :" <<endl; return (width * height); } }; class Triangle: public Shape{ public: Triangle( int a=0, int b=0):Shape(a, b) { } int area () { cout << "Triangle class area :" <<endl; return (width * height / 2); } };
#include "person.h" int main() { Shape *shape; Rectangle rec(10,7); Triangle tri(10,5); // Stores the address of the rectangle shape = &rec; // Call the rectangular area function area shape->area(); // Store the address of the triangle shape = &tri; // Call the area function area of triangle shape->area(); return 0; }
Output results:
Result analysis: the calling function area() is set to the version in the base class by the compiler, which is the so-called static polymorphism, or static link function call, which is ready before the program execution. Sometimes this is also called early binding because the area() function is already set during program compilation.
improvement:
class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } virtual int area()//Add virtual to the base class { cout << "Parent class area :" <<endl; return 0; } };
Output results:
Result analysis: after improvement, the compiler looks at the pointer content rather than its type. Therefore, since the addresses of the objects of the tri and rec classes are stored in * shape, their respective area() functions will be called. Each subclass has a separate implementation of the function area(). This is the general use of polymorphism. With polymorphism, you can have multiple different classes, functions with the same name but different implementations, and function parameters can even be the same.
Virtual functions: virtual functions are functions declared in the base class using the keyword virtual. When you redefine a virtual function defined in the base class in a derived class, you tell the compiler not to statically link to the function. What we want is that at any point in the program, we can choose the function to call according to the type of object to be called. This operation is called dynamic link or late binding.
Pure virtual function: you may want to define a virtual function in the base class so that it can be redefined in the derived class to better apply to objects, but you can't give a meaningful implementation of the virtual function in the base class. Pure virtual functions will be used at this time.
We can rewrite the virtual function area() in the base class as follows:
class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } // pure virtual function virtual int area() = 0; // =0 tells the compiler that the function has no body and the above virtual function is a pure virtual function. };
2. Special polymorphism function
example:
#define PERSON_H #include <iostream> using namespace std; //Base class People class People{ public: People(char *name, int age); void display(); protected: char *m_name; int m_age; }; People::People(char *name, int age): m_name(name), m_age(age){} void People::display(){ cout<<m_name<<"this year"<<m_age<<"Years old, a homeless man."<<endl; } //Derived class Teacher class Teacher: public People{ public: Teacher(char *name, int age, int salary); void display(); private: int m_salary; }; Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){} void Teacher::display(){ cout<<m_name<<"this year"<<m_age<<"Years old, is a teacher, every month"<<m_salary<<"Yuan of income."<<endl; } // Main function #include "person.h" #include <iostream> using namespace std; int main(){ People *p = new People("Zhi Gang Wang", 23); p -> display(); p = new Teacher("Zhao Hongjia", 45, 8200); p -> display(); return 0; }
Output results:
Result analysis: when the base class pointer p points to the object of the derived class Teacher, although the member variable of Teacher is used, its member function is not used, resulting in different output results (Zhao Hongjia was a Teacher, but the output results show that he is a homeless person), which is not in line with our expectations. In other words, you can only access the member variables of the derived class through the base class pointer, but you cannot access the member functions of the derived class.
Solution: use virtual functions.
Declare display() as a virtual function in the base class Person and the derived class Teacher:
virtual void display(); //Declare as virtual function
Output results:
Summary: with virtual functions, when the base class pointer points to the base class object, the members of the base class (including member functions and member variables) are used, and when it points to the derived class object, the members of the derived class are used. In other words, the base class pointer can do things in the way of the base class or the derived class. It has a variety of forms or expressions.
The purpose of providing polymorphism in C + + is to provide "all-round" access to member variables and member functions of all derived classes (including direct derivation and indirect derivation) through base class pointers, especially member functions. Without polymorphism, we can only access member variables. The virtual function is called according to the pointer. The virtual function of which class is called when the pointer points to the object of which class.
3. Polymorphism of destructor
We know that sometimes a base class pointer points to a derived class object dynamically generated by the new operator; At the same time, the dynamically generated objects with the new operator are released by deleting the pointer to it. If a base class pointer points to a derived class object dynamically generated by the new operator, and the object is released by releasing the base class pointer, the program may be incorrect.
example:
class CShape //Base class { public: ~CShape() { cout << "CShape::destrutor" << endl; } }; class CRectangle : public CShape //Derived class { public: int w, h; //Width and height ~CRectangle() { cout << "CRectangle::destrutor" << endl; } }; // Main function int main() { CShape* p = new CRectangle; delete p; return 0; }
Output results:
Result analysis: delete p; Only the destructor that triggered CShape class is called, and the destructor that did not trigger crictangle class is called. This is because the statement is statically bound. When the compiler compiles to this time, it is impossible to know which type of object P points to. It only determines that the destructor of csshape class should be called according to the type of P as csshape *.
Solution: add the virtual keyword before the destructor and declare it as a virtual function.
class CShape{ public: virtual ~CShape() { cout << "CShape::destrutor" << endl; } };
Output results:
Result analysis: it shows that the destructor of the crtangle class has been called. In fact, the destructor of the derived class will automatically call the destructor of the base class.
As long as the destructor of the base class is a virtual function, the destructor of the derived class will automatically become a virtual destructor whether declared with the virtual keyword or not
4. Multiple inheritance
Multiple inheritance means that a subclass can have multiple parent classes, which inherits the characteristics of multiple parent classes.
C + + classes can inherit members from multiple classes. The syntax is as follows:
class <Derived class name>:<Inheritance mode 1><Base class name 1>,<Inheritance mode 2><Base class name 2>,... { <Derived class body> };
Among them, the access modifier inheritance method is one of public, protected or private, which is used to modify each base class, which is separated by commas.
example:
// Base class Shape class Shape { public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } protected: int width; int height; }; // Base class PaintCost class PaintCost { public: int getCost(int area) { return area * 70; } }; // Derived class class Rectangle: public Shape, public PaintCost { public: int getArea() { return (width * height); } }; // Main function int main(void) { Rectangle Rect; int area; Rect.setWidth(5); Rect.setHeight(7); area = Rect.getArea(); // Area of output object cout << "Total area: " << Rect.getArea() << endl; // Total output cost cout << "Total paint cost: $" << Rect.getCost(area) << endl; return 0; }
Output results:
Multiple inheritance is prone to naming conflicts, such as diamond inheritance, as shown in the following figure:
Class A derives from class B and class C, and class D inherits from class B and class C. at this time, the member variables and member functions in class A inherit from class D into two parts, one from A – > b – > D and the other from A – > C – > D.
Retaining multiple members of the indirect base class with the same name in a derived class, although different data can be stored in different member variables, in most cases, this is redundant: retaining multiple member variables not only takes up more storage space, but also easily leads to life name conflicts. If class A has a member variable a, it will be ambiguous to directly access a in class D. the compiler does not know whether it comes from a -- > b – > D or a – > C – > D. The following is the specific implementation of diamond inheritance:
//Indirect base class A class A{ protected: int m_a; }; //Direct base class B class B: public A{ protected: int m_b; }; //Direct base class C class C: public A{ protected: int m_c; }; //Derived class D class D: public B, public C{ public: void seta(int a){ m_a = a; } //name conflict void setb(int b){ m_b = b; } //correct void setc(int c){ m_c = c; } //correct void setd(int d){ m_d = d; } //correct private: int m_d; }; int main(){ D d; return 0; }
Class D code attempts to access the member variable m directly_ a. The result is an error because there is a member variable m in both class B and class C_ A (inherited from Class A), the compiler does not know which one to choose, so there is an ambiguity.
In order to eliminate ambiguity, we can use M_ The front of a indicates which class it comes from:
void seta(int a){ B::m_a = a; }
This code represents m using class B_ a. Of course, you can also use class C:
void seta(int a){ C::m_a = a; }
Virtual inheritance: solve the naming conflict and redundant data problems in multiple inheritance, so that only one member of the indirect base class is retained in the derived class.
example:
//Indirect base class A class A{ protected: int m_a; }; //Direct base class B class B: virtual public A{ //Virtual inheritance protected: int m_b; }; //Direct base class C class C: virtual public A{ //Virtual inheritance protected: int m_c; }; //Derived class D class D: public B, public C{ public: void seta(int a){ m_a = a; } //correct void setb(int b){ m_b = b; } //correct void setc(int c){ m_c = c; } //correct void setd(int d){ m_d = d; } //correct private: int m_d; }; int main(){ D d; return 0; }
This instance uses virtual inheritance to re implement the diamond inheritance shown in the above figure, so that only one member variable m is retained in derived class D_ a. Direct access will no longer be ambiguous.
The purpose of virtual inheritance is to make A class declare that it is willing to share its base class. The shared base class is called Virtual Base Class. In this example, A is A Virtual Base Class. Under this mechanism, no matter how many times the Virtual Base Class appears in the inheritance system, the derived class contains only one member of the Virtual Base Class.
4, Vector graph design
EasyX is a graphics library for C/C + +. After installation, it can help you quickly start graphics programming with C/C + + language. After referencing the header file of graphics, you can program.
1.main.cpp
(1) . window design
//Graphics canvas basic settings initgraph(640, 480);// Create window (width, height) setbkcolor(WHITE); // Set background color delay_ms(0);//Pauses the execution of the program for a period of time (milliseconds) setcolor(BLACK);//This method sets the color of the brush settextstyle(16, 0, _T("Consolas"));//Sets the current text properties for drawing output setbkmode(TRANSPARENT);//Set the background blending mode of the specified DC. The background blending mode is used with text, filling brush and when the brush is not solid. //enter + left click -- > new rectangle ""); //enter + right click -- > New Triangle ""); //enter + middle of scroll wheel -- > new composite graphics //ctrl + left click -- > copy graphic ""); //ctrl + right click -- > Paste graphic ""); //Vector is a vector type, which can hold many types of data, such as several integers, so it is called a container. Vector is an important member of C++ STL. When using it, you need to include the corresponding header file vector<Draw*>shapes; vector<Draw*>shapestmp; // push_back: in the vector class, it is used to add a data at the end of the vector. shapes.push_back(new CTriangle(CPoint(320, 320), CPoint(250, 340), CPoint(340, 450))); //shapes.push_back(new CTriangle(CPoint(10, 10), CPoint(150, 10), CPoint(150, 150))); shapes.push_back(new CRect(CPoint(200, 200), CPoint(300, 300))); shapes.push_back(new Comgraphics(CRect(CPoint(250, 50))));
(2) . mouse events
//move bool move_flag = false; bool copy_flag = false; bool redraw = true; //Record its coordinates when the mouse clicks int clickX, clickY; int copyX, copyY; int checkedid = -1; int copyid = -1; for (; is_run(); delay_fps(60)) { while (mousemsg()) {//Structure for saving mouse messages mouse_msg msg = getmouse();//Get a mouse message. If there is no mouse message in the current mouse message queue, it will wait all the time //Judge the movement of the mouse if (msg.is_move()) { if (checkedid != -1) { if (move_flag) { shapes[checkedid]->Move(msg.x - clickX, msg.y - clickY); } } clickX = msg.x; clickY = msg.y; redraw = true; } // Left mouse button else if (msg.is_left()) { // Judge whether the left mouse button is pressed if (msg.is_down()) { clickX = msg.x; clickY = msg.y; CPoint pt = CPoint(clickX, clickY); int isIn = 0; for (int i = 0; i < shapes.size(); i++) { if (shapes[i]->ptIn(pt)) { isIn = 1; //If the mouse is in the graphics area, set the moving flag to true move_flag = true; checkedid = i; redraw = true; break; } } if (isIn == 0) checkedid = -1; } else { move_flag = false; } } } // Redrawn if (redraw) { redraw = false; cleardevice(); for (int i = 0; i < shapes.size(); i++) { if (i == checkedid) shapes[i]->DrawColor(); else shapes[i]->Draw(); } } while (kbmsg()) { key_msg msgk = getkey(); if (msgk.key == key_enter && msgk.msg == key_msg_down) { mouse_msg msgm = getmouse(); if (msgm.is_left()) { // Judge whether the left mouse button is pressed if (msgm.is_down()) { shapes.push_back(new CRect(CPoint(msgm.x, msgm.y))); redraw = true; } } if (msgm.is_right()) { // Judge whether the right mouse button is pressed if (msgm.is_down()) { shapes.push_back(new CTriangle(CPoint(msgm.x, msgm.y))); redraw = true; } } if (msgm.is_mid()) { CRect r1 = CRect(CPoint(msgm.x, msgm.y)); // Determine whether the middle mouse button is pressed if (msgm.is_down()) { shapes.push_back(new Comgraphics(r1)); redraw = true; } } } if (msgk.key == key_control && msgk.msg == key_msg_down) { mouse_msg msgm = getmouse(); if (msgm.is_left()) { // Judge whether the left mouse button is pressed if (msgm.is_down()) { copyX = msgm.x; copyY = msgm.y; CPoint pt = CPoint(copyX, copyY); for (int i = 0; i < shapes.size(); i++) { if (shapes[i]->ptIn(pt)) { //If the mouse is in the graphics area, set the moving flag to true copy_flag = true; copyid = i; break; } } } } if (msgm.is_right()) { // Judge whether the right mouse button is pressed if (msgm.is_down()) { if (copy_flag == true) { shapes.push_back(&(shapes[copyid]->Clone())->Move(msgm.x - copyX, msgm.y - copyY)); redraw = true; } } } } } } closegraph();// close window return 0;
2.Draw.h
class CPoint; class CRect; class Draw { public: Draw(); Draw(const Draw& shape); virtual ~Draw(); virtual double GetArea() const; virtual bool ptIn(const CPoint& pt) const; virtual bool InRect(const CRect& rc) const; virtual void Draw() const; virtual void DrawColor(); virtual Draw* Clone() const; virtual Draw& Move(int nOffsetX, int nOffsetY); protected: string m_sName; }; class CPoint :public Draw { public: int m_nPosX; int m_nPosY; CPoint() { m_nPosX = 0; m_nPosY = 0; } CPoint(int nPosX, int nPosY); CPoint(const CPoint& pt); virtual ~CPoint(); double GetArea() const; bool ptIn(const CPoint& pt) const; bool InRect(const CRect& rc) const; void Draw() const; void DrawColor(); CPoint* Clone() const; CPoint& Move(int nOffsetX, int nOffsetY); }; class CTriangle :virtual public Draw { public: CTriangle() {} CTriangle(const CPoint& pt1, const CPoint& pt2, const CPoint& pt3); CTriangle(const CTriangle& rc); CTriangle(const CPoint& pt); virtual ~CTriangle(); double GetArea() const; bool ptIn(const CPoint& pt) const; bool InRect(const CRect& rc) const; void Draw() const; void DrawColor(); Draw* Clone() const; Draw& Move(int nOffsetX, int nOffsetY); CPoint m_pts[3]; }; class CRect :virtual public Draw { public: CRect() {} CRect(CPoint pt1, CPoint pt2); CRect(const CRect& rc); CRect(CPoint pt1); virtual ~CRect(); double GetArea() const; bool ptIn(const CPoint& pt) const; bool InRect(const CRect& rc) const; void Draw() const; void DrawColor(); Draw* Clone() const; Draw& Move(int nOffsetX, int nOffsetY); CPoint m_ptLT; CPoint m_ptBR; }; class Comgraphics :public CRect, public CTriangle { public: Comgraphics(const CRect& pt1); Comgraphics(const Comgraphics& rc); Comgraphics(const CPoint pt1); virtual ~Comgraphics(); double GetArea() const; bool ptIn(const CPoint& pt) const; bool InRect(const CRect& rc) const; void Draw() const; void DrawColor(); Draw* Clone() const; Draw& Move(int nOffsetX, int nOffsetY); CPoint m_pt1; CPoint m_pt2; };
3.Draw.cpp
Draw::Draw() { } Draw::Draw(const Draw& shape) { m_sName = shape.m_sName; } Draw::~Draw() { } double Draw::GetArea() const { return 0; } bool Draw::ptIn(const CPoint& pt) const { return false; } bool Draw::InRect(const CRect& rc) const { return false; } void Draw::Draw() const { } void Draw::DrawColor() { } Draw* Draw::Clone() const { return new Draw(*this); } Draw& Draw::Move(int nOffsetX, int nOffsetY) { return *this; } //CPoint CPoint::CPoint(int nPosX, int nPosY) { m_nPosX = nPosX; m_nPosY = nPosY; } CPoint::CPoint(const CPoint& pt) { m_nPosX = pt.m_nPosX; m_nPosY = pt.m_nPosY; } CPoint::~CPoint() { //cout << "CPoint::~CPoint()\n"; } double CPoint::GetArea() const { return 0; } bool CPoint::ptIn(const CPoint& pt) const { return false; } bool CPoint::InRect(const CRect& rc) const { return rc.ptIn(*this); } void CPoint::Draw() const { circle(m_nPosX, m_nPosY, 2); } void CPoint::DrawColor() { } CPoint* CPoint::Clone() const { return new CPoint(*this); } CPoint& CPoint::Move(int nOffsetX, int nOffsetY) { m_nPosX += nOffsetX; m_nPosY += nOffsetY; return *this; } //CTriangle CTriangle::CTriangle(const CTriangle& tri) { for (int i = 0; i < 3; i++) { m_pts[i] = tri.m_pts[i]; } } CTriangle::~CTriangle() { //cout << "CTriangle::~CTriangle()\n"; } CTriangle::CTriangle(const CPoint& pt1, const CPoint& pt2, const CPoint& pt3) { m_pts[0] = pt1; m_pts[1] = pt2; m_pts[2] = pt3; } CTriangle::CTriangle(const CPoint& pt) { CPoint* pt1 = new CPoint(pt.m_nPosX + 100, pt.m_nPosY + 90); CPoint* pt2 = new CPoint(pt.m_nPosX, pt.m_nPosY + 90); m_pts[0] = pt; m_pts[1] = *pt1; m_pts[2] = *pt2; } Draw& CTriangle::Move(int nOffsetX, int nOffsetY) { for (int i = 0; i < 3; i++) { m_pts[i].Move(nOffsetX, nOffsetY); } return *this; } double CTriangle::GetArea() const { int x1, y1, x2, y2, x3, y3; x1 = m_pts[0].m_nPosX; y1 = m_pts[0].m_nPosY; x2 = m_pts[1].m_nPosX; y2 = m_pts[1].m_nPosY; x3 = m_pts[2].m_nPosX; y3 = m_pts[2].m_nPosY; double bottomLine = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); double verticalLine1 = abs((y1 - y2) * x3 - (x1 - x2) * y3 + (x1 - x2) * y2 - (y1 - y2) * x2); double verticalLine2 = sqrt(pow(y1 - y2, 2) + pow(x1 - x2, 2)); double verticalLine = verticalLine1 / verticalLine2; return (verticalLine * bottomLine) / 2.0; } bool CTriangle::ptIn(const CPoint& pt) const { CTriangle c1 = CTriangle(m_pts[0], m_pts[1], pt); CTriangle c2 = CTriangle(m_pts[1], m_pts[2], pt); CTriangle c3 = CTriangle(m_pts[2], m_pts[0], pt); double totalArea = c1.GetArea() + c2.GetArea() + c3.GetArea(); if (totalArea == this->GetArea()) return true; else return false; } bool CTriangle::InRect(const CRect& rc) const { return rc.ptIn(m_pts[0]) && rc.ptIn(m_pts[1]) && rc.ptIn(m_pts[2]); } void CTriangle::Draw() const { int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY, m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY }; setfillcolor(RGB(0xFF, 0xFF, 0xFF)); fillpoly(4, poly); } void CTriangle::DrawColor() { int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY, m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY }; setfillcolor(RGB(0xFF, 0xA5, 0x00)); fillpoly(4, poly); } Draw* CTriangle::Clone() const { return new CTriangle(*this); } //CRect CRect::CRect(CPoint pt1, CPoint pt2) { m_ptLT = CPoint(min(pt1.m_nPosX, pt2.m_nPosX), min(pt1.m_nPosY, pt2.m_nPosY)); m_ptBR = CPoint(max(pt1.m_nPosX, pt2.m_nPosX), max(pt1.m_nPosY, pt2.m_nPosY)); } CRect::CRect(const CRect& rc) { m_ptLT = rc.m_ptLT; m_ptBR = rc.m_ptBR; } CRect::CRect(CPoint pt1) { m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY); m_ptBR = CPoint(pt1.m_nPosX + 100, pt1.m_nPosY + 100); } CRect::~CRect() { // cout << "CRect::CRect()\n"; } double CRect::GetArea() const { return (m_ptBR.m_nPosX - m_ptLT.m_nPosX) * (m_ptBR.m_nPosY - m_ptLT.m_nPosY); } bool CRect::ptIn(const CPoint& pt) const { return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) && (pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY); } bool CRect::InRect(const CRect& rc) const { return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR); } void CRect::Draw() const { // Store the x,y coordinates of n vertices int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY, m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY }; // To draw a polygon with n vertices, the first parameter must be passed in n+1, pts and the coordinates of the last vertex are the same as the first //drawpoly(5, pts); setfillcolor(RGB(0xFF, 0xFF, 0xFF)); fillpoly(5, pts); } void CRect::DrawColor() { int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY, m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY }; // To draw a polygon with n vertices, the first parameter must be passed in n+1, pts and the coordinates of the last vertex are the same as the first setfillcolor(RGB(0xFF, 0xA5, 0x00)); fillpoly(5, pts); } Draw* CRect::Clone() const { return new CRect(*this); } Draw& CRect::Move(int nOffsetX, int nOffsetY) { m_ptLT.Move(nOffsetX, nOffsetY); m_ptBR.Move(nOffsetX, nOffsetY); return *this; } //Comgraphics Comgraphics::Comgraphics(const CRect& pt1) { m_pt1.m_nPosX = pt1.m_ptBR.m_nPosX; m_pt1.m_nPosY = pt1.m_ptLT.m_nPosY + (pt1.m_ptBR.m_nPosY - pt1.m_ptLT.m_nPosY) / 2; m_pt2.m_nPosX = pt1.m_ptLT.m_nPosX + (pt1.m_ptBR.m_nPosX - pt1.m_ptLT.m_nPosX) / 2; m_pt2.m_nPosY = pt1.m_ptBR.m_nPosY; m_ptLT = pt1.m_ptLT; m_ptBR = pt1.m_ptBR; } Comgraphics::Comgraphics(const Comgraphics& rc) { m_pt1 = rc.m_pt1; m_pt2 = rc.m_pt2; m_ptBR = rc.m_ptBR; m_ptLT = rc.m_ptLT; } Comgraphics::Comgraphics(const CPoint pt1) { m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY); m_ptBR = CPoint(pt1.m_nPosX + 60, pt1.m_nPosY + 80); } Comgraphics::~Comgraphics() { cout << "Comgraphics::~Comgraphics()" << endl; } double Comgraphics::GetArea() const { return 0.0; } bool Comgraphics::ptIn(const CPoint& pt) const { return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) && (pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY); } bool Comgraphics::InRect(const CRect& rc) const const { return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR); } void Comgraphics::Draw() const { // Store the x,y coordinates of n vertices int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY, m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY }; // To draw a polygon with n vertices, the first parameter must be passed in n+1, pts and the coordinates of the last vertex are the same as the first //drawpoly(5, pts); setfillcolor(GREEN); fillpoly(5, pts); line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY); line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY); line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY); } void Comgraphics::DrawColor() { // Store the x,y coordinates of n vertices int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY, m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY }; // To draw a polygon with n vertices, the first parameter must be passed in n+1, pts and the coordinates of the last vertex are the same as the first setfillcolor(YELLOW); fillpoly(5, pts); line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY); line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY); line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY); } Draw* Comgraphics::Clone() const { return new Comgraphics(*(this)); } Draw& Comgraphics::Move(int nOffsetX, int nOffsetY) { m_ptLT.Move(nOffsetX, nOffsetY); m_ptBR.Move(nOffsetX, nOffsetY); m_pt1.Move(nOffsetX, nOffsetY); m_pt2.Move(nOffsetX, nOffsetY); return *this; }
Operation results: