简体   繁体   English

在C ++中实现虚函数和继承

[英]implementing virtual function and inheritance in C++

So I have these header files: 所以我有这些头文件:

Shape.h: Shape.h:

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

Trig.h: 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
};

but when I try to implement Trig.cpp, I get errors. 但是当我尝试实现Trig.cpp时,出现错误。 I tried : 我试过了 :

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

I've looked through the internet, but I don't seem to do the inheritance properly. 我已经浏览了互联网,但似乎无法正确进行继承。 [My code MUST have header file that includes the declarations only!... Requirements of the assignment!] [我的代码必须具有仅包含声明的头文件!...分配要求!]

I'm new in using both inheritance and virtual functions in C++ [I've used inheritance in Java] 我是在C ++中同时使用继承和虚函数的新手[我在Java中使用继承]

And concerning the virtual functions.. is there any difference in their implementation than in normal functions ? 关于虚拟功能,它们的实现与正常功能有什么区别吗? [I understand the difference in the behavior]. [我了解行为上的差异]。

In a comment you explain that 评论中,您解释说

“i get the error: undefined reference to `Shape::Shape()'” “我收到错误:对`Shape :: Shape()'的未定义引用”

That means that you have forgotten to provide an implementation of that constructor. 这意味着您忘记了提供该构造函数的实现。

Now, with the technical problem fixed, look at the design. 现在,解决技术问题后,看看设计。

The first two methods suffer from two maladies: (1) although they should never mutate an object they are not declared const , so they cannot be called on a const object, and (2) the get prefix reduces readability, is more to type and has no general advantage. 前两个方法有两个弊端:(1)尽管它们永远都不应突变对象,但它们并未声明为const ,因此无法在const对象上调用它们;(2) get前缀降低了可读性,其类型更多,并且没有一般优势。 I've found a get prefix useful in some rare circumstances as a disambiguation device, but all usages I've seen by beginners have been inappropriate copying of a Java convention, which makes sense in Java but not in C++. 我发现get前缀在某些罕见的情况下可用作消歧设备,但是初学者看到的所有用法都不适当地复制了Java约定,这在Java中是有意义的,但在C ++中是没有意义的。 So, instead of … 所以,而不是…

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

do

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

Then, the method … 然后,该方法...

bool isLegal(Shape shape);

is wrong in so many ways… Ouch! 在很多方面都是错的...哎呀! But let's start with the purely technical. 但是,让我们从纯粹的技术开始。

From a purely technical point of view it is needlessly inefficient to pass the argument by value, which incurs a copy operation for each call. 从纯粹的技术角度来看,按值传递参数是不必要的,这会导致每次调用都进行复制操作。 Instead pass the object by reference. 而是通过引用传递对象。 And make that a reference to const , in order to support const objects and rvalue objects as arguments: 并引用const ,以支持const对象和rvalue对象作为参数:

bool isLegal(Shape const& shape);

Next, naming: isLegal is an ungood name because most any C++ object will be legal. 接下来,命名: isLegal是一个不好的名字,因为大多数任何C ++对象都是合法的。 It would have to be, say, pornographic and residing in a non-Western country, in order to become illegal. 为了成为非法,它必须是色情的并且居住在一个非西方国家中。 And I can't for the life of me think of any way to make an object pornographic, or make it reside in some specific geographic region. 而且我一辈子都无法想像使物体色情或使其驻留在某些特定地理区域的任何方法。

So, 所以,

bool isValid(Shape const& shape);

Next, low level design, there is no good reason to have that non- virtual method as an ordinary member function, because that requires that you call it on an object. 接下来,是低级设计,没有充分的理由将非virtual方法用作普通成员函数,因为这要求您在对象上调用它。 But all the information it needs is in the ordinary argument. 但是它需要的所有信息都是普通的论点。 We can see this confusion in the derived class, where … 我们可以在派生类中看到这种混淆,其中……

bool isLegal(Trig trig);//override

is not at all an override: it's technically an overload of the function name, which means, just a different function with the same name. 根本没有覆盖:技术上来说,它是函数名称的重载 ,也就是说,只是具有相同名称的另一个函数。 There's no virtuality here, no override. 这里没有虚拟性,没有替代。 And it is not needed. 并不需要。

So, make that a static member function, which does not have to be called on an object: 因此,使该static成员函数不必在对象上调用:

static bool isValid(Shape const& shape);

Finally, higher level design, the whole machinery of C++ constructors and destructors is there in order to avoid such methods and checking. 最后,在更高层次的设计中,C ++构造函数和析构函数的全部机制都存在,以避免这种方法和检查。

The idea is that you … 这个想法是你……

  • Establish a valid object in every constructor. 在每个构造函数中建立一个有效的对象。

  • Keep the object valid in every method. 使对象在每种方法中均有效。

Then the object simply can't become invalid. 这样,对象就不会变得无效。 This approach is called single phase construction , and the properties of the object that makes it “valid' are known as the class' class invariant . 这种方法称为单阶段构造 ,并且使它“有效”的对象的属性称为类的类不变 Which should be established by every constructor, and maintained by every method. 应该由每个构造函数建立,并由每个方法维护。

This means, final version, the isValid function IS REMOVED : it has no job to do, because that job is (properly) done by the constructor(s) and the methods. 这意味着,最终版本的isValid函数已删除 :它没有工作要做,因为该工作(正确地)由构造函数和方法完成。

Okay, there are some technical challenges with single phase construction, in particular how to do derived class specific initialization in a base class constructor. 好的,单阶段构造存在一些技术挑战,特别是如何在基类构造函数中进行派生类特定的初始化。 This is covered by the C++ FAQ . C ++常见问题解答对此进行了介绍。 It's often a good idea to read the FAQ. 阅读常见问题解答通常是个好主意。

The first version is correct: 第一个版本是正确的:

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

It will compile, but it will not link. 它将编译,但不会链接。 The reason is that you have declared a parameterless constructor of Shape , but you failed to define it. 原因是您已声明 Shape的无参数构造函数,但未能定义它。 Eiher add a definition 艾尔(Eiher)添加定义

Shape::Shape() {..}

or if the default constructor is OK, remove the declaration from the Shape's header. 或者,如果默认构造函数为OK,则从Shape的标头中删除声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM