Experiment 4: Inheritance

1. Experimental task 2

The program source code is as follows:

 1 #include <iostream>
 2 #include<typeinfo>
 3 
 4 class Graph{
 5     public:
 6         virtual void draw(){
 7             std::cout<<"Graph::draw():just as an interface\n";
 8         }
 9 };
10 
11 class Rectangle : public Graph
12 {
13     public:
14         void draw(){
15             std::cout<<"Rectangle::draw(): programs of draw a rectangle\n";
16         }
17 };
18 
19 class Circle : public Graph
20 {
21     public:
22         void draw(){
23             std::cout<<"Circle::draw(): programs of draw a circle\n";
24         }
25 };
26 
27 void fun(Graph *ptr){
28     std::cout << "Pointer type:"<<typeid(ptr).name()<<"\n";
29     std::cout << "RTTI type:"<<typeid(*ptr).name()<<"\n";
30     ptr -> draw();
31 }
32 int main(){
33     Graph g1;
34     Rectangle r1;
35     Circle c1;
36     g1.draw();
37     r1.draw();
38     c1.draw();
39     
40     std::cout << "\n";
41     
42     r1.Graph::draw();
43     c1.Graph::draw();
44     
45     std::cout << "\n";
46     fun(&g1);
47     fun(&r1);
48     fun(&c1);
49 }

The screenshot before modification is:

 

 

The operation results after adding virtual are shown in the figure below:

 

 

Summary:

1. It can be observed that the ptr successfully points to the derived class at runtime, but the ptr pointer itself is still of Graph class. What the first 5, 6, 9 numbers and the letter P are still unknown.

2. When a derived class has a member with the same name as the base class, the function member of the derived class will be run first. The base class member can be run after being identified by the binary scope identifier

For example, r1.Graph::draw();    c1.Graph::draw();

3. Type compatibility principle: derived class objects can be used as base class objects, but when used as base class objects, only the part of the interface used as the base class can be used. Therefore, the member type declared by the function is Graph, and draw () must be displayed as the base class.

2. Experimental task 3

The following is Battery.hpp

 1 #pragma once
 2 class Battery {
 3 public:
 4     int get_capacity() {
 5         return capacity;
 6     }
 7     Battery(int obj = 70):capacity(obj){}
 8 private:
 9     int capacity;
10 };

The following is Car.hpp

 1 #pragma once
 2 #include<iostream>
 3 #include<string>
 4 using namespace std;
 5 class Car {
 6 private:
 7     string maker;
 8     string model;
 9     int year;
10     int odometers;
11 public:
12     Car();
13     Car(string m1, string m2, int y) :maker(m1), model(m2), year(y), odometers(0) {};
14     void info();
15     void update_odometers(int n);
16 };
17 void Car::info() {
18     cout << maker << endl;
19     cout << model << endl;
20     cout << year << endl;
21     cout << odometers << endl;
22 }
23 void Car::update_odometers(int n) {
24     if (n >= odometers)
25         odometers = n;
26     else
27         cout << "data is error!";
28 }

The following is ElectricCar.hpp

ElectricCar.hpp

The following is task3.cpp

 1 #include <iostream>
 2 #include "electricCar.hpp"
 3 
 4 int main()
 5 {
 6     using namespace std;
 7 
 8     // test class of Car
 9     Car oldcar("Audi", "a6", 2016);
10     cout << "--------oldcar's info--------" << endl;
11     oldcar.update_odometers(25000);
12     oldcar.info();
13 
14     cout << endl;
15 
16     // test class of ElectricCar
17     ElectricCar newcar("Tesla", "model s", 2016);
18     newcar.update_odometers(12500);
19     cout << "\n--------newcar's info--------\n";
20     newcar.info();
21 }

 

 

 

  3. Experimental task 4

pets.hpp

 1 #pragma once
 2 #include<string>
 3 #include<iostream>
 4 using namespace std;
 5 class MachinePets {
 6 private:
 7     string nickname;
 8 public:
 9     MachinePets();
10     MachinePets(const string s):nickname(s){}
11     const string get_nickname() {
12         return nickname;
13     }
14     virtual string talk() {
15         return"talk~";
16     }
17 };
18 class PetCats : public MachinePets{
19 public:
20     PetCats(const string st):MachinePets(st){}
21     string talk() {
22         return "miao wu~";
23     }
24 };
25 class PetDogs :public MachinePets{
26 public:
27     PetDogs();
28     PetDogs(const string s1):MachinePets(s1){
29         
30     }
31     string talk() {
32         return "wang!wang!";
33     }
34 };

 

task4.cpp

 1 #include <iostream>
 2 #include "pets.hpp"
 3 
 4 void play(MachinePets* ptr)
 5 {
 6     std::cout << ptr->get_nickname() << " says " << ptr->talk() << std::endl;
 7 }
 8 
 9 int main()
10 {
11     PetCats cat("miku");
12     PetDogs dog("da huang");
13 
14     play(&cat);
15     play(&dog);
16 }

The test screenshot is as follows:

 

  Summary:

1. It can be observed that the ptr successfully points to the derived class at runtime, but the ptr pointer itself is still of Graph class. What the first 5, 6, 9 numbers and the letter P are still unknown.

2. When a derived class has a member with the same name as the base class, the function member of the derived class will be run first. The base class member can be run after being identified by the binary scope identifier

For example, r1.Graph::draw();    c1.Graph::draw();

3. Type compatibility principle: derived class objects can be used as base class objects, but when used as base class objects, only the part of the interface used as the base class can be used. Therefore, the member type declared by the function is Graph, and draw () must be displayed as the base class

4. Get the type name with typeid().name()

5. When initializing in an inherited class, the constructor should be placed in front of braces, otherwise the problem of redefinition will occur.

Posted by PcGeniusProductions on Sat, 27 Nov 2021 20:32:40 -0800