Subclass in C++ - C++ 中的子类

1. Subclass in C++

You are already introduced with inheritance in OOP chapter. So, let’s make a subclass of a superclass.
您已经在 OOP 一章中了解了继承。因此,让我们做一个 superclasssubclass

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>
#include <string>using namespace std;class Student    // base class
{string name;public:string getName(){return name;}void setName(string n){name = n;}void printAbout(){cout << "I am a student" << endl;}
};class Undergraduate: public Student   //derived class
{
public:void printAbout(){cout << "I am an Undergraduate" << endl;}
};int main()
{Student s;Undergraduate u;s.printAbout();u.printAbout();return 0;
}

Output

I am a student
I am an Undergraduate

class Undergraduate : public Student - Undergraduate is the name of a class which is a subclass or derived class of the Student class.

Both classes are having functions with the same name - printAbout. But the definitions (or statements) of the functions are different. These type of functions are called polymorphic functions.
这两个类都具有相同名称的函数 - printAbout。但是函数的定义 (或声明) 不同。这些类型的函数称为多态函数。

polymorphic [,pɒlɪ'mɔːfɪk]:adj. 多态的,多形的,多形态的,多晶形的 (等于 polymorphous)
derived class:子类或派生类

Execution of printAbout from s ( object of Student class ) will print I am a Student. while from u ( object of Undergraduate class ) will print I am an Undergraduate.

Thus, the objects of each of these classes are calling their respective printAbout function.
因此,这些类的每一个的对象都在调用它们各自的 printAbout 函数。

So, here Student is a base class or parent class and Undergraduate is a derived class or child class.

2. Protected

Any protected member of a class (variable or function) can be accessed within that class or its subclass. It cannot be accessed outside that.
一个类 (变量或函数) 的任何受保护成员都可以在该类或其子类中访问。除此之外无法访问。

Let’s see an example.

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>
#include <string>using namespace std;class Student        // base class
{
protected:string name;public:void setName(string n){name = n;}
};class Undergraduate: public Student   //derived class
{
public:void printName(){cout << name << endl;}
};int main()
{Undergraduate u;u.setName("xyz");u.printName();return 0;
}

Output

xyz

In this example, Student is the parent class and Undergraduate is its child class.

In the Student class, we made name protected. So, it can be accessed directly within its subclass Undergraduate. And we did the same. We accessed the name variable directly in the function printName of its subclass.
Student 类中,我们将其命名为 protected。因此,可以直接在其 Undergraduate 子类中进行访问。我们做的一样。我们直接在其子类的函数 printName 中访问名称变量。

We first created an object u of the subclass Undergraduate. Since an object of a subclass can access any of the members of its parent class, so u called the function setName of its parent class with a string parameter "xyz". This string got assigned to the variable name thus making the value of name as "xyz" for the object u.
我们首先创建了 Undergraduate 子类的对象 u。由于子类的对象可以访问其父类的任何成员,因此 u 调用其父类的函数 setName (字符串参数 "xyz")。该字符串被分配给变量 name,从而使对象 uname 的值成为 “xyz”

u then called the function printName which printed the value of name i.e., xyz.

Now, let’s see what would happen if we try to call a member function of a subclass by the object of the parent class.
现在,让我们看看如果尝试通过父类的对象调用子类的成员函数会发生什么。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>
#include <string>using namespace std;class Student        //base class
{
protected:string name;public:void setName(string n){name = n;}
};class Undergraduate: public Student   //derived class
{
public:void printName(){cout << name << endl;}
};int main()
{Student s;s.setName("xyz");s.printName();return 0;
}

Console

09:49:40 **** Build of configuration Debug for project hello_world ****
make all
Building file: ../src/hello_world.cpp
Invoking: GCC C++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/hello_world.d" -MT"src/hello_world.o" -o "src/hello_world.o" "../src/hello_world.cpp"
../src/hello_world.cpp: In function ‘int main()’:
../src/hello_world.cpp:39:4: error: ‘class Student’ has no member named ‘printName’s.printName();^
src/subdir.mk:18: recipe for target 'src/hello_world.o' failed
make: *** [src/hello_world.o] Error 109:49:40 Build Finished (took 678ms)

The above code is giving us error. This is because s is an object of the Student class and we are trying to call the function printName of the class Undergraduate by the object of its parent class Student which is invalid.

An object of a subclass can access the members of its superclass (if not private) but an object of a superclass can’t access the members of its subclasses.
子类的对象可以访问其父类的成员 (如果不是私有的),但是父类的对象则不能访问其子类的成员。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class C1
{
public:C1(){}protected:void m1(){cout << "This is protected function of superclass" << endl;}
};class C2: public C1
{
public:C2(){}void m2(){m1(); // Since m1 is a protected function of C1, therefore it can be called in its subclass (C2)}
};int main()
{C1 s;C2 a;a.m2(); // 'a' an object of C2 can access m2( public function of C2)// s.m2(); // Remove this from comment and you will get an error because 's' is an object of superclass can't access function 'm2' of subclass// a.m1(); // This will also generate an error because m1 is a protected function of C1 and so cannot be called outside C1 or its subclass(C2)return 0;
}

Output

This is protected function of superclass
//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class C1
{
public:C1(){}protected:void m1(){cout << "This is protected function of superclass" << endl;}
};class C2: public C1
{
public:C2(){}void m2(){m1(); // Since m1 is a protected function of C1, therefore it can be called in its subclass (C2)}
};int main()
{C1 s;C2 a;a.m2(); // 'a' an object of C2 can access m2( public function of C2)// s.m2(); // Remove this from comment and you will get an error because 's' is an object of superclass can't access function 'm2' of subclassa.m1(); // This will also generate an error because m1 is a protected function of C1 and so cannot be called outside C1 or its subclass(C2)return 0;
}
10:00:03 **** Build of configuration Debug for project hello_world ****
make all
Building file: ../src/hello_world.cpp
Invoking: GCC C++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/hello_world.d" -MT"src/hello_world.o" -o "src/hello_world.o" "../src/hello_world.cpp"
../src/hello_world.cpp: In function ‘int main()’:
../src/hello_world.cpp:21:7: error: ‘void C1::m1()’ is protectedvoid m1()^
../src/hello_world.cpp:46:7: error: within this contexta.m1(); // This will also generate an error because m1 is a protected function of C1 and so cannot be called outside C1 or its subclass(C2)^
make: *** [src/hello_world.o] Error 1
src/subdir.mk:18: recipe for target 'src/hello_world.o' failed10:00:04 Build Finished (took 685ms)

3. Subclass with constructor

We can normally have constructors for both base and derived class to initialize their respective members. The constructor of the derived class can call the constructor of the base class, but the inverse is not true.
通常,我们可以同时具有基类和派生类的构造函数来初始化其各自的成员。派生类的构造函数可以调用基类的构造函数,但反之则不成立。

3.1 Calling base class constructor having no parameter

If the base class constructor has no parameter, then it will be automatically called by the compiler whenever the derived class constructor will be called, even if we do not explicitly call it.
如果基类构造函数没有参数,那么只要派生类构造函数被调用,编译器就会自动调用它,即使我们没有显式调用它。

Look at the following to understand it.

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class A
{
public:A(){cout << "Constructor of A" << endl;}
};class B: public A
{
public:B(){cout << "Constructor of B" << endl;}
};int main()
{B b;return 0;
}

Output

Constructor of A
Constructor of B

While calling the constructor of any class, the compiler first automatically calls the constructor of its parent class. This is the reason that while calling the constructor of class B, the compiler first called the constructor of its parent class A and then the constructor of B. Thus when the constructor of B was called, the compiler first called the constructor of A thus printing Constructor of A and after that Constructor of B.
在调用任何类的构造函数时,编译器首先会自动调用其父类的构造函数。这就是为什么在调用类 B 的构造函数时,编译器首先调用其父类 A 的构造函数,然后再调用 B 的构造函数。因此,当调用 B 的构造函数时,编译器首先调用 A 的构造函数,从而打印出 A 的构造函数,然后打印出 B 的构造函数。

While calling the constructor of any class, the compiler first automatically calls the constructor of its parent class.
在调用任何类的构造函数时,编译器首先会自动调用其父类的构造函数。

Let’s see another example where the constructor of the parent class gets automatically called first.
让我们看另一个例子,其中父类的构造函数首先被自动调用。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class A
{
public:A(){cout << "Constructor of A" << endl;}
};class B: public A
{
public:B(){cout << "Constructor of B" << endl;}
};class C: public B
{
public:C(){cout << "Constructor of C" << endl;}
};int main()
{cout << "\nCreating object of A :" << endl;A a;cout << "\nCreating object of B :" << endl;B b;cout << "\nCreating object of C :" << endl;C c;return 0;
}

Output


Creating object of A :
Constructor of ACreating object of B :
Constructor of A
Constructor of BCreating object of C :
Constructor of A
Constructor of B
Constructor of C

Here, when the object of A was created, its constructor was called, printing Constructor of A.
在这里,当创建 A 的对象时,将调用其构造函数,并打印 A 的构造函数。

When the object of B was created, the compiler first called the constructor of its parent class A, printing Constructor of A and after that printing Constructor of B.
当创建对象 B 时,编译器首先调用其父类 A 的构造函数,打印 A 的构造函数,然后打印 B 的构造函数。

Similarly, when the constructor of C was called on creating its object, first the constructor of its parent class B was called. On calling the constructor of B, the constructor of A got called printing Constructor of A followed by Constructor of B. At last, Constructor of C got printed.
同样,在创建对象时调用 C 的构造函数时,首先调用其父类 B 的构造函数。在调用 B 的构造函数时,A 的构造函数被调用打印 A 的构造函数,随后是 B 的构造函数。最后,打印出了 C 的构造函数。

3.2 Calling parameterized base class constructor

Unlike parent class constructors having no parameter, parameterized parent class constructors are not called automatically while calling its child class constructor.
与没有参数的父类构造函数不同,参数化的父类构造函数在调用其子类构造函数时不会自动调用。

To call a parent class constructor having some parameter form the constructor of its subclass, we have to use the initialization list of its subclass. Let’s see how.
要调用具有某些参数的父类构造函数作为其子类的构造函数,我们必须使用其子类的初始化列表。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class A
{
public:A(int l){cout << "Length : " << l << endl;}
};class B: public A
{
public:B() : A(20){cout << "This is constructor of B" << endl;}
};int main()
{B b;return 0;
}

Output

Length : 20
This is constructor of B

As in the above example, a parameterized constructor of a class is called from its subclass by writing it in the initialization list with its argument written within brackets.
如上面的示例所示,通过在初始化列表中将参数写在括号中,从而从其子类调用父类的参数化构造函数。

In this example, when we created an object b of the class B, the constructor B got called. Since the constructor of A is written in its initialization list, the constructor of A got called first with a value 10 passed as its argument.
在这个例子中,当我们创建类 B 的对象 b 时,调用了构造函数 B。由于 A 的构造函数写在其初始化列表中,因此 A 的构造函数首先被调用,并传递了一个值为 10 的参数。

Thus, its parameter l became equal to 10 and the body of the constructor of A got executed. After that the body of the constructor of B got executed.
因此,它的参数 l 等于 10,并且执行了 A 构造函数的主体之后,执行了 B 的构造函数的主体。

Let’s see one more example.
让我们再看一个例子。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class A
{int l1;
public:A(int z) : l1(z){cout << "l1 : " << l1 << endl;}
};class B: public A
{int l2;
public:B(int x, int y) : A(x), l2(y){cout << "l2 : " << l2 << endl;}
};int main()
{B b(5, 10);return 0;
}

Output

l1 : 5
l2 : 10

In this example, we passed the values 5 and 10 to the constructor of class B while creating its object. So the values 5 and 10 got assigned to x and y respectively.
在此示例中,我们在创建类 B 的对象时将值 5 和 10 传递给了类 B 的构造函数。因此,将值 5 和 10 分别分配给了 xy

In the initializer list of the constructor of B, the value of x i.e. 5 got passed as the argument of the constructor of A and the value of l2 became 10.
B 的构造函数的初始化程序列表中,将 x 的值即 5 传递为 A 的构造函数的参数,而 l2 的值变为 10。

Again, the constructor of A first got called making the value of l1 as 5. After the body of A got executed, the compiler went back to the body of the constructor of B and executed it.
再次,A 的构造函数首先被调用,将 l1 的值设为 5。执行完 A 的主体之后,编译器返回到 B 的构造函数的主体并执行它。

Let’s see one more example of printing the area and perimeter of a rectangle.
让我们再看一个打印矩形的面积和周长的示例。

//============================================================================
// Name        : std::class
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#include <iostream>using namespace std;class Rectangle
{int length;int breadth;public:Rectangle(int l, int b){length = l;breadth = b;}int getArea(){return length * breadth;}int getPerimeter(){return 2 * (length + breadth);}
};class Square: public Rectangle
{
public:Square(int a) : Rectangle(a, a){}
};int main()
{Square s(2);int area, p;area = s.getArea();p = s.getPerimeter();cout << "Area : " << area << endl;cout << "Perimeter : " << p << endl;return 0;
}

Output

Area : 4
Perimeter : 8

We know that square is also a rectangle with the same length and breadth. This is what we did in the constructor of Square.
我们知道正方形是具有相同长度和宽度的矩形。这就是我们在 Square 的构造函数中所做的。

We created an object s of class Square and passed 2 at the time of creating it. So, this 2 will be passed to the constructor of class Square. Hence, the value of a will be 2.
我们创建了一个类 Square 的对象 s,并在创建时传递了 2。因此,这 2 将被传递给 Square 类的构造函数。因此,a 的值将为 2。

In the initialization list of the constructor of Square, constructor of its superclass Rectangle is being called with the value of a as 2, thus making the value of both its length and breadth equal to a i.e. 2.
Square 的构造函数的初始化列表中,其超类 Rectangle 的构造函数被调用,其 a 的值为 2,因此使其长度和宽度的值均等于 a 的值,即 2。

Finally, in the main function, we used the object s of the class Square to call two functions of its parent class Rectangle getArea and getPerimeter.
最后,在 main 函数中,我们使用了 Square 类的对象 s 调用了其父类 Rectangle getAreagetPerimeter 的两个函数。

Practice everytime you get a chance.
每次有机会时都要练习。

inheritance [ɪnˈherɪtəns]:n. 继承,遗传,遗产
class:类
derived class:继承类,派生类
subclass:子类
base class:基类
superclass:超类,父类
passion [ˈpæʃn]:n. 激情,热情,酷爱,盛怒

References

https://www.codesdope.com/cpp-subclass/

Subclass in C++ - C++ 中的子类相关推荐

  1. java 调用父级方法_java子类调用父类的方法中包含子类重写的实例方法

    # 看题目是不是很绕,这个我也不知道怎么才能更简单的表达了 # 先看代码: public class Common { public static void main(String[] args) { ...

  2. VS中查看子类对象内存分布的方法

    文章目录 1 VS中查看子类对象内存分布的方法 1 VS中查看子类对象内存分布的方法 设置vs编译器: 在命令行中添加选项(打印指定类的内存分布):/d1 reportSingleClassLayou ...

  3. PHP 父类静态方法中调用子类静态方法

    get_called_class() 获取调用该方法的类,如果是在子类中调用父类方法,则返回子类的类名. 或者用static关键字: static::class 如果有多个子类,要在父类中调用子类方法 ...

  4. c++中父类子类对象指针相互转换,成员函数调用方式

    c++中父类子类对象指针相互转换的问题: 在面向对象开发时,某些场景下需要将子类对象的指针强转成父类指针进行调用,或者,将父类指针强转成子类指针进行调用,这个时候成员函数调用规律是什么样的? 规律:不 ...

  5. coco数据集(yoloV5格式)中生成子类数据集

    从coco数据集(yoloV5格式)中生成子类数据集. import os from tqdm import tqdmnames = ['person', 'bicycle', 'car', 'mot ...

  6. java如何调用父类的实例对象_java子类调用父类的方法中包含子类重写的实例方法...

    java子类调用父类的方法中包含子类重写的实例方法 # 看题目是不是很绕,这个我也不知道怎么才能更简单的表达了 # 先看代码: public class Common { public static ...

  7. java子类的子类_java中的子类是什么

    java中的子类是什么 发布时间:2020-06-26 15:57:41 来源:亿速云 阅读:152 作者:Leah java中的子类是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编 ...

  8. 父类卡子类卡java_Java中关于子类覆盖父类的抛出异常问题

    Java中子类覆盖父类方法抛出异常不能比父类多,这个表述不够准确. 准确一点的描述为: 子类抛出的异常类型不能比父类抛出的异常类型更宽泛.假设父类抛出异常ParentException,另外有两个子类 ...

  9. SSH整合中,使用父action重构子类action类.(在父类中获取子类中的泛型对象)

    import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type;import com.opensymphony.xw ...

最新文章

  1. 【干货合辑】+你有什么独家数据库优化技巧?
  2. 机房收费系统=三层+设计模式
  3. 第2章 fping、hping应用
  4. 缠绕多年的PCIE通道数问题终于完全明白了,欢迎指正
  5. [转]设定version 更新js缓存
  6. Java实现的词频统计
  7. rs(0)与rs(字段名)的区别
  8. 海龟绘图两小时上手C语言 - 4 任意螺旋线
  9. arm 服务器优势,零的突破 戴尔正式宣布基于ARM架构服务器
  10. 剑指offer面试题63. 股票的最大利润(动态规划)
  11. 一个90后草根站长的内心独白
  12. vue+video.js实现前端视频流(hls、MP4、flv)
  13. appscan 9.0.3.12 版本下载
  14. Icode编程>>>图形化编程>>>1级训练场>>>基础训练【1】
  15. ios-webkit-debug-proxy 说明
  16. 如何知道计算机是否支持64位,查看CPU是否支持64位操作系统的简单方法
  17. 数据管理平台(DMP)简介
  18. C++线程池原理及创建
  19. MySQL索引的详细分析和数据结构
  20. 如何申请edi许可证

热门文章

  1. PC端微信聊天记录备份文件在哪儿?
  2. lan的以太网标准_并非所有以太网电缆都是平等的:通过升级,您可以获得更快的LAN速度...
  3. mysql 最大值65536_SQL server事物复制报错:要复制的 LOB 数据的长度(xxxxx)超出了配置的最大值 65536...
  4. methods: 68368 65536
  5. 自然语言处理方面的顶会
  6. c++通讯录管理系统(函数,指针,结构体)
  7. 【LeetCode】初级算法:数组
  8. java打开jnlp_如何打开jnlp
  9. 腾讯微信客服电话号码是多少
  10. Jquery点击切换播放不同的Flv视频文件