面向对象设计的重要目的之一就是代码重用,而继承和多态是面向对象的两个最主要的特征。本文将主要围绕c++中的继承展开讨论,并以一些简单的例子来说明。
一.首先观察在继承中,成员对象的初始化。
1.创建派生类对象时,程序首先创建基类对象,这意味着基类对象应当在程序进入派生类构造函数前被创建。
2.派生类构造函数应通过成员初始化列表将基类信息传递给基类的构造函数。
3.派生类的构造函数总是调用一个基类构造函数。
请看如下一个简单的继承问题:
基类的头文件base.h:
#ifndef BASE_H_
#define BASE_H_
class base
{
private:
int s;
public:
base(int age);//基类的构造函数
};
#endif
base.cpp:
#include<base.h>
#include<iostream>
using namespace std;
base::base(int age)
{
s = 6;
cout << "这是基类的构造函数" <<"\n";
cout << "hello my name is Zjh" << "\n";
cout << "I am " <<age<<" years old \n";
}
子类 son.h
#ifndef SON_H_
#define SON_H_
#include<base.h>
class son : public base //继承
{
private:
int a;
public:
son (int age); //子类的构造函数
};
#endif
子类 son.cpp
#include<son.h>
#include<iostream>
#include<string>
using namespace std;
son::son(int age ) :base(22) //基类构造函数有输入参数,子类应显式的调用基类的构造函数
{
a = 10;
cout << "我是子类的构造函数" << "\n";
cout << "hello my name is anni" << "\n";
cout << "I am " << age << " years old \n";
}
主函数:
#include<iostream>
#include<base.h>
#include<son.h>
int main()
{
son x(18);
}
程序运行结果:
在这里插一段,由于自己在学习Python的时候发现类的继承中,若要初始化父类的构造函数需利用super实现
"""Python super example"""
class A:
def __init__(self,a):
print('这是A类的构造函数')
self.a=a
def add(self,a,b):
return a+b
class B(A):
def __init__(self):
#super(B, self).__init__(10)
print('这是B类的构造函数')
x=B()
print(x.add(2,3))
子类构造函数中没有super程序输出为:
加上super后:
可以看出加上super后可实现父类的初始化。
二、虚函数,多态性是面向对象程序设计的重要特征,重载和虚函数是体现多态性的两个重要手段。虚函数体现了多态的灵活性,进一步减少了冗余的信息。
说通俗一点就是:虚函数可以让成员函数操作一般化,即用基类的指针指向不同的派生类对象时,基类指针调用其成员虚函数,会调用真正指向对象的成员函数,而不是基类定义的成员函数(派生类改写了该成员函数),如没有虚函数则不管基类指针指向哪个派生类对象,调用时都会调用基类定义的那个函数。
这里一定要注意多态,多态的关键就是一切用基类的指针或引用来操作对象。
请看下面的例子:
为了方便看我把几个子文件放在了一起子类继承父类,并且都有test方法,但是其实现的功能不一样,父类test实现两个数的相加,子类test实现两个数相乘。
/*base.h 头文件*/
#ifndef BASE_H_
#define BASE_H_
class base
{
public:
int test(int a, int b);//基类中的test实现两个数相加
};
#endif
/*son.h 头文件*/
#ifndef SON_H_
#define SON_H_
#include<base.h>
class son : public base
{
public:
int test(int a, int b);//子类test实现两个数相乘
};
#endif
/*base.cpp文件*/
#include<base.h>
#include<iostream>
int base::test(int a, int b)
{
int c = a+b;
std::cout << "a=" << a << ";\n";
std::cout << "b=" << b << ";\n";
std::cout << "a+b的值为:" << c << "\n";
return c;
}
/*son.cpp 文件*/
#include<son.h>
#include<iostream>
int son::test(int a, int b)
{
int c = a*b;
std::cout << "a=" << a << ";\n";
std::cout << "b=" << b << ";\n";
std::cout << "a*b的值为:" << c << "\n";
return c;
}
当我的main函数是这样时请观察输出:
#include<iostream>
#include<base.h>
#include<son.h>
int main()
{
base x0;
son x1;
x0.test(2, 3);
x1.test(2, 3);
}
此时程序分别调用各自的test方法,基类输出a+b;子类输出a*b;但是并没有做到真正的多态(多态的关键就是一切用基类的指针或引用来操作对象。)。
当main函数为如下程序时请观察输出:
#include<iostream>
#include<base.h>
#include<son.h>
int main()
{
base x0;
son x1;
base *p1 = &x0;
base *p2 = &x1;
//base *p1 = new son;
//base *p2 = new base;
p1->test(2, 3);
p2->test(2, 3);
}
程序输出:
可以看出此时程序的输出并不是我们想要的那样,而是都调用了基类的test函数。
这就需要引入虚函数了,此时仅需修改base.h文件
在test前加上virtual关键字(注意构造函数不能是虚函数)
#ifndef BASE_H_
#define BASE_H_
class base
{
public:
virtual int test(int a, int b);//基类中的test实现两个数相加 (此时test定义为虚函数)
};
#endif
程序的输出:
可以看出加上虚函数后可实现基类指针调用真正指向对象的成员函数。以上为鄙人的一些愚见,特此总结,若有问题欢迎交流!好了,今天就总结到这溜了溜了!