【问题标题】:implementing virtual function and inheritance in C++在 C++ 中实现虚函数和继承
【发布时间】:2012-09-15 11:52:57
【问题描述】:

所以我有这些头文件:

形状.h:

class Shape
{
public:
    Shape();
    virtual ~Shape();
    virtual double getArea();
    virtual void printDraw();
    bool isLegal(Shape shape);
};

Trig.h:

class Trig : public Shape
{
public:
    Trig(Point pointA, Point pointB, Point pointC);
    virtual ~Trig();
    virtual double getArea();//override
    virtual void printDraw();//override
    bool isLegal(Trig trig);//override
};

但是当我尝试实现 Trig.cpp 时,我得到了错误。 我试过了:

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

我浏览了互联网,但我似乎没有正确地进行继承。 [我的代码必须有只包含声明的头文件!...分配的要求!]

我是在 C++ 中同时使用继承和虚函数的新手 [我在 Java 中使用过继承]

关于虚函数..它们的实现与普通函数有什么不同吗? [我理解行为上的差异]。

【问题讨论】:

  • 第一版Trig::Trig(Point pointA...)对于构造函数的实现基本正确。确切的代码是什么样的,你得到了什么错误?
  • 如果我写:Trig::Trig(Point pointA, Point pointB, Point pointC) {..} 我得到错误:未定义对 `Shape::Shape()' 的引用
  • 您的Trig 构造函数将隐式调用Shape 的构造函数(默认情况下为默认构造函数),因为它派生自Shape。因此,您还必须为Shape 实现至少一个构造函数。你这样做了吗? (错误消息似乎表明您没有。)
  • 这很可能意味着您还没有实现Shape 的一些其他功能。确保你全部实现它们(或不声明它们)。
  • 请参阅stackoverflow.com/questions/1963926/… 了解有关虚拟表 (vtable) 是什么的一般答案。

标签: c++ inheritance header virtual


【解决方案1】:

评论中你解释了

“我收到错误:未定义对 `Shape::Shape()' 的引用”

这意味着您忘记提供该构造函数的实现。

现在,解决了技术问题,看看设计。

前两种方法有两个缺点:(1)虽然它们不应该改变一个对象,但它们没有被声明为const,因此它们不能在const对象上调用,以及(2)get前缀降低了可读性,更多的类型并且没有一般优势。我发现get 前缀在一些罕见的情况下作为消歧工具很有用,但我看到的所有初学者的用法都是不恰当地复制 Java 约定,这在 Java 中有意义,但在 C++ 中没有意义。所以,而不是……

virtual double getArea();
virtual void printDraw();

virtual double area() const;
virtual void print() const;

那么,方法……

bool isLegal(Shape shape);

在很多方面都是错误的……哎哟!但让我们从纯粹的技术开始。

从纯粹的技术角度来看,按值传递参数是不必要的低效,这会导致每次调用的复制操作。而是通过引用传递对象。并引用const,以支持const 对象和右值对象作为参数:

bool isLegal(Shape const& shape);

接下来,命名:isLegal 是一个不好的名称,因为大多数 C++ 对象都是合法的。例如,它必须是色情的并且居住在非西方国家,才能成为非法的。而且我这辈子都想不出任何办法让一个对象色情,或者让它驻留在某个特定的地理区域。

所以,

bool isValid(Shape const& shape);

接下来,低级设计,没有充分的理由将非virtual 方法作为普通成员函数,因为这需要您在对象上调用它。但它需要的所有信息都在普通参数中。我们可以在派生类中看到这种混乱,其中……

bool isLegal(Trig trig);//override

根本不是覆盖:从技术上讲,它是函数名称的 重载,这意味着,只是具有相同名称的不同函数。这里没有虚拟,没有覆盖。而且不需要。

因此,将其设为 static 成员函数,不必在对象上调用它:

static bool isValid(Shape const& shape);

最后,更高级别的设计,C++ 构造函数和析构函数的整个机制都在那里,以避免这些方法和检查。

这个想法是你……

  • 在每个构造函数中建立一个有效的对象。

  • 在每个方法中保持对象有效。

那么对象就不会变得无效。这种方法称为单阶段构造,使其“有效”的对象的属性称为类的类不变量。每个构造函数都应该建立,每个方法都应该维护它。

这意味着,最终版本,isValid 函数已删除:它没有工作要做,因为该工作(正确)由构造函数完成( s) 和方法。

好的,单阶段构造存在一些技术挑战,特别是如何在基类构造函数中进行派生类特定的初始化。 C++ FAQ 涵盖了这一点。阅读常见问题解答通常是个好主意。

【讨论】:

  • 哇...谢谢您的帮助 :) 关于设计的一些事情.. 嗯.. 设计主要是由课程人员提供的,他们说这是一个糟糕的设计,但我们必须坚持这是因为作业的目的是练习具体的事情,而且由于时间不够,最好按照给定的设计工作。
  • " 必须是色情的并且居住在非西方国家,才能成为非法的。而且我终其一生都想不出任何方法来制作反对色情,或使其驻留在某个特定的地理区域。”度过了我的一天:D
【解决方案2】:

第一个版本是正确的:

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

它会编译,但不会链接。原因是您声明了 Shape 的无参数构造函数,但未能定义它。或者添加一个定义

Shape::Shape() {..}

或者,如果默认构造函数没有问题,则从 Shape 的标题中删除声明。

【讨论】:

    猜你喜欢
    • 2012-04-22
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多