• 5、继承与派生6-虚基类


    当某类的部分或全部直接基类是从另一个共同基类派生而来时,在这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称。在派生类的对象中,这些同名数据成员在内存中同时拥有多个拷贝,同一个函数名会有多个映射。我们可以使用作用域分辨符来惟一标识并分别访问他们,也可以将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样就解决了同名成员的惟一标识问题。

    虚基类的声明是在派生类的定义过程中进行的,语法形式

    class 派生类名:virtual 继承方式 基类名

    在多继承的情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。声明了虚基类之后,虚基类的成员在进一步派生过程中和派生类一起维护同一个内存数据拷贝。

    如:

    有一个基类B0,声明了数据成员nV和函数fun,由B0公有派生产生了类B1和B2,与前一个例子不同的是派生时声明了B0为虚基类,再以B1、B2作为基类共同公有派生了新类D1,在派生类中我们不再添加新的同名成员,这时的D1类中,通过B1、B2两条派生路径继承来的基类B0中的成员nV和fun只有一份拷贝。

    使用了虚基类之后,在派生类D1中只有唯一的数据成员nV和fun。在建立D1类对象的模块中,直接使用”对象名.成员名“方式就可以惟一标识和访问这些成员

    如:

    #include<iostream>
    using namespace std;
    class B0
    {
    public:
    int nV;
    void fun(){cout<<"Member of B0"<<endl;}
    };
    class B1:virtual public B0 //B0为虚基类,派生了B1类
    {
    public:
    int nV1;
    };
    class B2:virtual public B0//B0为虚基类,派生了B2类
    {
    public:
    int nV2;

    };
    class D1:public B1,public B2 //派生类D1定义
    {
    public:
    int nVd;
    void fund(){cout<<"Member of D1"<<endl;}
    };
    int main()
    {
    D1 d1;
    d1.nV=2;
    d1.fun();

    getchar();
    }

    结果:

    Member of B0

    比较一下使用作用域分辨符和虚基类技术的这两个例子,前者在派生类中拥有同名成员的多个拷贝,分别通过直接基类名来唯一标识,可以存放不同的数据、进行不同的操作。后者之维护一份成员拷贝。相比之下,前者可以容纳更多的数据,后者使用更为简洁,内存空间更为节省。

    3、虚基类及其派生类构造函数

    如果虚基类声明有非默认形式的(即带形参的)构造函数,并且没有声明默认形式的构造函数,事情就比较麻烦了。这时,在整个继承关系中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化

    如:

    #include<iostream>
    using namespace std;
    class B0
    {

    public:
    B0(int n){nV=n;}
    int nV;
    void fun(){cout<<"Member of B0"<<endl;}
    };
    class B1:virtual public B0 //B0为虚基类,派生了B1类
    {
    public:
    B1(int a):B0(a){}
    int nV1;
    };
    class B2:virtual public B0//B0为虚基类,派生了B2类
    {
    public:
    B2(int a):B0(a){}
    int nV2;

    };
    class D1:public B1,public B2 //派生类D1定义
    {
    public:
    D1(int a):B0(a),B1(a),B2(a){}
    int nVd;
    void fund(){cout<<"Member of D1"<<endl;}
    };
    int main()
    {
    D1 d1(1);
    d1.nV=2;
    d1.fun();

    getchar();
    }

    建立D1类对象d1时,通过D1类的构造函数的初始化列表,不仅直接调用了虚基类构造函数B0,对从B0继承的成员nV进行了初始化,而且还调用了直接基类B1和B2的构造函数B1()和B2()的初始化列表中也都有对基类B0的初始化。这样岂不是从虚基类继承来的成员nV初始化了三次?其实c++编译器的处理方式是,在上面程序中,将建立对象d1时,即D1是最远派生类。建立一个对象时,如果这个对象中含有虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的而且,只有最远派生类的构造函数会调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用都自动被忽略。

    linequ.h文件(包括基类和派生类的定义)

     1 //linequ.h文件一,类定义
     2 //包括矩阵类Matrix和线性方程组类linequ的定义
     3 #include<iostream>
     4 #include<cmath>
     5 using namespace std;
     6 class Matrix  //基类Matrix定义
     7 {
     8 public:      //外部接口
     9     Matrix(int dims=2);//构造函数
    10     ~Matrix();//析构函数
    11     void setMatrix(double *rmatr); //矩阵赋初值
    12     void printM();//显示矩阵
    13 protected:    //保护数据成员
    14     int index;//矩阵的维数
    15     double *MatrixA;//矩阵存放数组首地址
    16 };
    17 class Linequ :public Matrix //公有派生类Linequ定义
    18 {
    19 public:    //外部接口
    20     Linequ(int dims = 2);//构造函数
    21     ~Linequ();//析构函数
    22     void setLinequ(double *a,double *b);//方程赋值
    23     void printL();//显示方程
    24     int Solve();//全选主元高斯消去法求解方程
    25     void showX();//显示方程的解
    26 private:
    27     double *sums;//方程右端项
    28     double *solu;//方程的解
    29 
    30 };
    View Code

    linequ.cpp基类和派生类各成员函数的实现 

      1 #include"linequ.h"//包含类的定义头文件
      2 //基类成员函数的实现
      3 void Matrix::setMatrix(double *rmatr)//设置矩阵
      4 {
      5     for (int i = 0; i < index*index; i++)
      6         *(MatrixA + i) = rmatr[i];        //矩阵成员赋初值
      7 }
      8 Matrix::Matrix(int dims)        //矩阵Matrix类的构造函数
      9 {
     10     index = dims;//保护数据赋值
     11     MatrixA = new double[index*index];//动态内存分配
     12 }
     13 Matrix::~Matrix()//矩阵Matrix类的析构函数
     14 {
     15     delete[] MatrixA;//内存释放
     16 }
     17 void Matrix::printM()//显示矩阵的元素
     18 {
     19     cout << "The Matrix is:" << endl;
     20     for (int i = 0; i < index; i++)
     21     {
     22         for (int j = 0; j < index; j++)
     23             cout << *(MatrixA + i*index + j) << " ";
     24         cout << endl;
     25 
     26     }
     27 }
     28 //派生类的成员函数的实现
     29 Linequ::Linequ(int dims) :Matrix(dims)        //派生类Linequ的构造函数
     30 {
     31     sums = new double[dims];//动态内存分配
     32     solu = new double[dims];
     33 }
     34 Linequ::~Linequ()//派生类Linequ的析构函数
     35 {
     36     delete[] sums;            //释放内存
     37     delete[] solu;
     38 }
     39 void Linequ::setLinequ(double *a, double *b)    //设置线性方程组
     40 {
     41     setMatrix(a);        //调用基类函数
     42     for (int i = 0; i < index; i++)
     43         sums[i] = b[i];
     44 }
     45 void Linequ::printL()        //显示线性方程组
     46 {
     47     cout << "The Line equation is:" << endl;
     48     for (int i = 0; i < index; i++)
     49     {
     50         for (int j = 0; j < index; j++)
     51             cout << *(MatrixA + i*index + j) << " ";
     52         cout << sums[i]<<endl;
     53     }
     54 }
     55 void Linequ::showX()        //输出方程的解
     56 {
     57     cout << "The Result is:" << endl;
     58     for (int i = 0; i < index; i++)
     59     {
     60         cout << "X[" << i << "]=" << solu[i] << endl;
     61     }
     62 }
     63 int Linequ::Solve()        //全选主元高斯消去法求解方程
     64 {
     65     int *js, l, k, i, j, is, p, q;
     66     double d, t;
     67     js = new int[index];
     68     l = 1;
     69     for (k = 0; k <= index - 2; k++)            //消去过程
     70     {
     71         d = 0.0;//用于存放每次寻找到的最大值
     72         for (i = k; i <= index - 1; i++)
     73             for (j = k; j <= index - 1; j++)
     74             {
     75                 t = fabs(MatrixA[i*index + j]);
     76                 if (t > d)
     77                 {
     78                     d = t;
     79                     js[k] = j; //存放最大值的列坐标
     80                     is = i;//存放最大值的行坐标
     81                 }
     82             }
     83             if (d + 1.0 == 1.0)l = 0;
     84             else
     85             {
     86                 if (js[k] != k) //交换最大值对应列与k对应的主对角位置的列
     87                     for (i = 0; i <= index - 1; i++)
     88                     {
     89                     p = i*index + k; q = i*index + js[k];
     90                     t = MatrixA[p];
     91                     MatrixA[p] = MatrixA[q];
     92                     MatrixA[q] = t;
     93                     }
     94                 if (is != k)//交换最大值对应行与k对应的主对角位置的行
     95                 {
     96                     for (j = k; j <= index - 1; j++)
     97                     {
     98                         p = k*index + j;
     99                         q = is*index + j;
    100                         t = MatrixA[p];
    101                         MatrixA[p] = MatrixA[q];
    102                         MatrixA[q] = t;
    103                     }
    104                     t = sums[k]; 
    105                     sums[k] = sums[is];
    106                     sums[is] = t;
    107                 }
    108             }//else
    109             if (l == 0)
    110             {
    111                 delete[] js;
    112                 cout << "fail" << endl;
    113                 return (0);
    114             }
    115             d = MatrixA[k*index+k];
    116             for (j = k + 1; j <= index - 1; j++)
    117             {
    118                 p = k*index + j;
    119                 MatrixA[p] = MatrixA[p] / d;
    120             }
    121             sums[k] = sums[k] / d;
    122             for (i = k + 1; i <= index - 1; i++)
    123             {
    124                 for (j = k + 1; j <= index - 1; j++)
    125                 {
    126                     p = i*index + j;
    127                     MatrixA[p] = MatrixA[p] - MatrixA[i*index + k] * MatrixA[k*index + j];
    128                 }
    129                 sums[i] = sums[i] - MatrixA[i*index + k] * sums[k];
    130             }
    131     }
    132     d = MatrixA[(index-1)*index+index-1];
    133     if (fabs(d) + 1.0 == 1.0)
    134     {
    135         delete[] js;
    136         cout << "fail" << endl;
    137         return (0);
    138     }
    139     solu[index - 1] = sums[index - 1] / d;        //回代过程
    140     for (i = index - 2; i >= 0; i--)
    141     {
    142         t = 0.0;
    143         for (j = i + 1; j <= index - 1; j++)
    144             t = t + MatrixA[i*index + j] * solu[j];
    145         solu[i] = sums[i] - t;
    146     }
    147     js[index - 1] = index - 1;
    148     for (k = index - 1; k >= 0;k--)
    149         if (js[k] != k)
    150         {
    151         t = solu[k];
    152         solu[k] = solu[js[k]];
    153         solu[js[k]] = t;
    154         }
    155     delete[] js;
    156     return (1);
    157 }
    View Code

    7_9.cpp主函数

     1 #include"linequ.h"
     2 int main(int argc, char *agrv[])
     3 {
     4     double a[] =            //方程系数矩阵
     5     {
     6         0.2368,0.2471,0.2568,1.2671,
     7         0.1968,0.2071,1.2168,0.2271,
     8         0.1581,1.1675,0.1768,0.1871,
     9         1.1161,0.1254,0.1397,0.1490
    10     };
    11     double b[4] =            //方程组右端项
    12     {1.8471,1.7471,1.6471,1.5471};
    13     Linequ equl(4);//定义一个四元方程组对象
    14     equl.setLinequ(a,b);//设置方程组
    15     equl.printL();//输出方程组
    16     if (equl.Solve())//求解方程组
    17         equl.showX();//输出方程组的解
    18     else
    19         cout << "Fail" << endl;
    20     return 0;
    21 }
    View Code
  • 相关阅读:
    5月读书日志
    把代码搬到Git Hub 吧(一)
    RTX二次开发(二)(基于ASP.NET)
    RTX二次开发(一)(基于ASP.NET)
    文件夹下迭代查询文件
    JS URL传递中文参数时出现乱码的处理
    js实现上下滑动侧边栏
    基本select语句的生命周期
    NodeJs下的测试框架Mocha
    带新人感想
  • 原文地址:https://www.cnblogs.com/gary-guo/p/6247036.html
Copyright © 2020-2023  润新知