《面向对象程序设计-C++》实验五 虚函数的使用及抽象类

发布于:2025-05-09 ⋅ 阅读:(23) ⋅ 点赞:(0)

程序片段编程题

1.【问题描述】

基类shape类是一个表示形状的抽象类,area( )为求图形面积的函数。请从shape类派生三角形类(triangle)、圆类(circles)、并给出具体的求面积函数。注:圆周率取3.14

#include<iostream>
#include<cmath>
#define PI 3.14
using namespace std;
class shape
{
public:
    virtual float area()=0;
};

int main()
{
    shape *p;
    triangle t(3,4,5);
    circles c(10);
    p=&t;
    cout<<"triangle area:"<<p->area()<<endl;
    p=&c;
    cout<<"circles area:"<<p->area()<<endl;
}

这题常规补充三角形的面积公式和圆的面积公式就行了,but我现在C++有点忘记构造函数怎么写了,而且继承的时候public shape我还多添了一个冒号,基本功都不太行辣!

class triangle:public shape
{
	int a,b,c;
public:
	triangle(int a,int b,int c):a(a),b(b),c(c){}
    float area(){
    	float p=(a+b+c)/2.0;
    	return sqrt(p*(p-a)*(p-b)*(p-c)); 
	}
};
class circles:public shape
{
	int r;
public:
	circles(int a):r(a){}
    float area(){
    	return 3.14*r*r;
	}
};

2.【问题描述】

定义一个抽象类Base,在该类中定义一个纯需函数virtual void abstractMethod() = 0;派生一个基于Base的派生类Derived,在派生类Derived的abstractMethod方法中输出"Derived::abstractMethod is called",最后编写主函数,其内容如下:

#include<iostream>
using namespace std;

class Base{
	public:
	virtual void abstractMethod() = 0;
};
class Derived:public Base{
	public:
	void abstractMethod(){
		cout<<"Derived::abstractMethod is called";
	}
};

int main()
{
    Base* pBase = new Derived;
    pBase->abstractMethod();
    delete pBase;
    return 0;
}

虚函数的继承和正常的继承好像其实差别不大......

class Base{
	public:
	virtual void abstractMethod() = 0;
};
class Derived:public Base{
	public:
	void abstractMethod(){
		cout<<"Derived::abstractMethod is called";
	}
};

程序设计题

1.录入下面程序,并分析结果

#include <iostream>
#include <complex>
using namespace std;
class Base
{
public:
    Base() {cout<<"Base-ctor"<<endl;}
    ~Base() {cout<<"Base-dtor"<<endl;}
    virtual void f(int){cout<<"Base::f(int)"<<endl;}
    virtual void f(double){cout<<"Base::f(double)"<<endl;}
    virtual void g(int i=10){cout<<"Base::g()"<<i<<endl;}
};

class Derived : public Base
{
public:
    Derived() {cout<<"Derived-ctor" <<endl;}
    ~Derived(){cout<<"Derived-dtor"<<endl;}
    void f(complex<double>) {
        cout<<"Derived::f(complex)"<<endl;
    }
    void g(int i=20){
        cout<<"Derived::g()"<<i<<endl;
    }
};
int main()
{
    cout<<sizeof(Base)<<endl;
    cout<<sizeof(Derived)<<endl;
    Base b;
    Derived d;
    Base *pb=new Derived;
    b.f(1.0);
    d.f(1.0);
    pb->f(1.0);
    b.g();
    d.g();
    pb->g();
    delete   pb;
    return 0;
}

我猜的结果和实际的结果——

事后诸葛亮:

相比之下,我错的地方有:

1.不知道sizeof多大

base类包含虚函数,因此会有一个虚表指针(vptr)。在大多数平台上,指针大小为4字节或8字节(取决于32位或64位系统)。因此,sizeof(Base)的输出通常是 8(64位)或 4(32位)。

2.构造派生类Derived前面是需要先构造基类的,所以开局还会有一个Base-ctor。

3.指针引用到new Derived实际上是需要重新构造一个类的,所以也有Base-ctor,Derived-ctor。但如果是引用到已经有的一个对象,比如d,就不需要重新构造了。

4.程序结束时,局部对象b和d也会被析构,分别调用Base和Derived的析构函数

5.

pb->f(1.0) 的行为

背景

  • pb 是一个指向 Derived 对象的 Base 类型指针。

  • f 是一个虚函数,因此会动态绑定到实际对象的类型(即 Derived 类)。

  • 1.0 是一个 double 类型的参数。

动态绑定过程

  1. 查找 Derived 类中的 f 函数:

    • Derived 类中定义了一个 f 函数:

      cpp

      复制

      void f(complex<double>) { cout << "Derived::f(complex)" << endl; }
    • 但这个函数的参数类型是 complex<double>,与 f(double) 不匹配。(complex<double> 是一个类类型,表示复数。它包含两个 double 类型的成员(实部和虚部)。double 是一个基本数据类型,表示双精度浮点数)

  2. 查找基类 Base 中的 f 函数:

    • Base 类中定义了两个 f 函数:

      cpp

      复制

      virtual void f(int) { cout << "Base::f(int)" << endl; }
      virtual void f(double) { cout << "Base::f(double)" << endl; }
    • 由于 Derived 类中没有匹配的 f(double) 函数,动态绑定会回退到基类的 f(double)

  3. 最终调用:

    • pb->f(1.0) 调用的是 Base::f(double),输出:

      Base::f(double)

6.

背景

  • pb 是一个指向 Derived 对象的 Base 类型指针。

  • g 是一个虚函数,因此会动态绑定到实际对象的类型(即 Derived 类)。

  • g 函数有一个默认参数。

动态绑定过程

  1. 查找 Derived 类中的 g 函数:

    • Derived 类中定义了一个 g 函数:

      cpp

      复制

      void g(int i = 20) { cout << "Derived::g()" << i << endl; }
    • 这个函数覆盖了基类 Base 中的 g 函数。

  2. 默认参数的解析:

    • 默认参数是在编译时解析的,而不是运行时。因此,pb->g() 的行为取决于 pb 的静态类型(即 Base 类型)。

    • Base 类型的 g 函数的默认参数是 10,因此 pb->g() 会使用 Base 类的默认参数 10

  3. 最终调用:

    • pb->g() 调用的是 Derived::g,但使用了 Base 类的默认参数 10,输出:

      Derived::g()10

2.录入下面程序,并分析结果

#include   <iostream>
using   namespace   std;
class   Base
{
public:
    Base():data(count)
    {
        cout<<"Base-ctor"<<endl;
        ++count;
    }
    ~Base()
    {
        cout<<"Base-dtor"<<endl;
        --count;
    }
    static int count;
    int data;
};
int Base::count;
class Derived  : public Base
{
public:
    Derived():data(count),data1(data)
    {
        cout<<"Derived-ctor"<<endl;
        ++count;
    }
    ~Derived()
    {
        cout<<"Derived-dtor"<<endl;
        --count;
    }
    static int count;
    int data1;
    int data;
};
int Derived::count=10;
int main()
{
    cout<<sizeof(Base)<<endl;//8
    cout<<sizeof(Derived)<<endl;//8
    Base* pb = new Derived[3];//Base-ctorDerived-ctor*3次 
    cout<<pb[2].data<<endl;//12
    cout<<((static_cast<Derived*>(pb))+2)->data1<<endl;//
    delete[] pb;//Derived-dtorBase-dtor*3次 
    cout<<Base::count<<endl;//
    cout<<Derived::count<<endl;//10
    return 0;
}

我的分析:

要崩溃了www

解释:

1.Base 类的大小为 4 字节,因为它只包含一个 int 类型的成员变量 data 和一个静态成员变量 count(静态成员变量不占用对象的内存)。Derived 类的大小为 12 字节,因为它继承了 Base 类的 data,并新增了两个 int 类型的成员变量 data1data。

2.在第三个对象构造时,Base::count 的值为 3,但 Derived 的构造函数中 data 被重新初始化为 Derived::count 的值,即 10。

3.data1 的值被覆盖为一个未定义的值(50331651),这可能是因为内存未正确初始化或存在其他问题

4.由于 pbBase 类型的指针,编译器只会调用 Base 的析构函数,而不会调用 Derived 的析构函数。这是因为 Base 的析构函数没有被声明为 virtual,导致多态行为失效。

5.Base::count 在析构完所有对象后为 0Derived::count 在析构完所有对象后为 13,因为 Derived 的析构函数没有被调用。


网站公告

今日签到

点亮在社区的每一天
去签到