2

我正在学习 c++ 继承,我来自 Java。为了训练,我制作了一个小型 java 示例并尝试将其转换为 c++,但我的 c++ 实现有很多问题。

这是我的接口 IShape.java。它代表了 Shape 的抽象。

public interface IShape {
    public void draw();
}

这是我实现Shape的Triangle.java。

public class Triangle implements IShape{
    @Override
    public void draw() {
        //draw code
    }
}

现在是 Main.java:

public class Main {
    public static void main(String[] args) {
        IShape someShape = new Triangle();
        someShape.draw();
    }
}

在java中一切都很好,但我的c++版本甚至没有编译:S 这是我的IShape.h c++文件。它应该类似于 IShape.java 接口。

#ifndef ISHAPE_H_
#define ISHAPE_H_

class IShape{

public:
    virtual void draw() = 0;

    //must have this because of compiler
    virtual ~IShape();
private:
    //an awesome thing in c++ is that I can also define private methods for my children to implement!
    virtual int compute_point() = 0;
};

#endif

现在我的 Triangle.cpp 文件:

#include "IShape.h"

class Triangle: public IShape {

protected:
    int max_size;

public:
    Triangle(){
        max_size = 255;//This triangle has a limited max size!
    }

    void draw() {
        //implementation code here
    }

private:
    int compute_point() {
        //implementation code here
    }
};

现在完成,我的 C++ 主要:

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#include "IShape.h"
#include "Triangle.cpp"

using namespace std;

int main( int argc, char *argv[]){

    IShape myShape = Triangle();
    myShape.draw();

    return EXIT_SUCCESS;
}

我的 C++ 主程序中有什么错误。因为我有几个问题,我会尝试列举它们:

  1. 它告诉我“mySHApe”是抽象的,而不是因为我在三角形类中实现了它!
  2. 即使我修复了第一个错误,我也无法调用“myShape.draw()”
  3. 我的朋友说我永远不应该包含 cpp 文件。但是如果我不包括三角形,我的 Main.cpp 怎么知道它存在?
  4. 有没有更好的方法在 C++ 中移植这个例子?还是我太“java-ed”了?

我已经阅读了几个关于 c++ 的链接和教程,每个链接和教程都以不同的方式教给我一些东西,因此我最终得到了很多定义并且有点困惑。我也搜索了 StackOverflow,但我发现的帖子对我没有帮助,它们通常指的是更复杂的问题。

我做错了什么,您可以提供哪些提示来改进我的代码风格?另外,对于文字墙感到抱歉,我正在努力解释自己,而不是被否决。

4

5 回答 5

3

在 C++ 中,为了实现多态性,您必须使用指针引用。具有自动存储的对象会被切片,在你的情况下,甚至不会被实例化。事实上,这条指令:

IShape myShape = Triangle();

将尝试实例化一个类型的对象IShape并为其分配一个临时Triangle对象。绝对不是你想要的。另一方面,这可以完成工作:

IShape* myShape = new Triangle(); // Using 
// ...
delete myShape;

但是,在现代 C++ 中,使用智能指针通常是个好主意。尝试以这种方式重写您的main()函数:

#include <memory> // For std::shared_ptr<>

int main( int argc, char *argv[])
{
    std::shared_ptr<IShape> myShape = std::make_shared<Triangle>();
    myShape->draw();

    return EXIT_SUCCESS;
}

另请注意,您有一个未提供定义的虚拟析构函数:

virtual ~IShape();

你应该提供一个。最简单的方法是以这种方式内联空主体:

virtual ~IShape() { }
于 2013-03-15T17:51:34.760 回答
1

IShape myShape = Triangle();这是试图创建一个IShape实例并将其分配给一个三角形。IShape如您所知,它是抽象的,所以我们不能这样做。

你想要的是一个指针。

IShape* myShape = new Triangle();

同时替换:

virtual ~IShape();virtual ~IShape() {}

于 2013-03-15T17:51:37.547 回答
1

这一切都源于您试图在这里实例化一个IShape 对象

IShape myShape = ...;

这与 RHS 上的内容无关。编译器会告诉你为什么你不能这样做。您需要一个IShape指针(如果您使用动态分配,则需要一个智能指针)。在此示例中,为简单起见,我们使用自动存储分配,但这只是一个细节:

Triangle t;           // default construct a Triangle object
IShape* myShape = &t; // IShape pointer points to a Triangle instance.
myShape->draw();      // calls Triangle::draw()

动态分配的一个例子是

std::unique_ptr<IShape> myShape(new Triangle());
myShape->draw();

其他问题:

  1. 缺少析构函数实现。给~IShape()一个空的主体,这样派生类就不会在不需要析构函数时强制实现。
  2. 受保护的数据可能会导致代码混乱。您应该考虑将其设为max_size私有。
  3. 使用构造函数初始化列表来初始化数据成员,而不是在构造函数体中为它们赋值:Triangle() : max_size(255) {}
于 2013-03-15T17:52:17.117 回答
1

这条线是你的问题:

IShape myShape = Triangle();

它创建一个临时Triangle对象,然后尝试IShape通过复制临时三角形来创建一个对象。但是IShape是抽象的,你不能创建这样的对象。

你想要的是有一个Triangle对象的句柄。在 C++ 中,句柄分为三种:引用、指针和智能指针。大多数情况下,您应该使用智能指针。

试试这个:

unique_ptr<IShape> myShape = new Triangle();

在 Java 中,每个具有非原始类型的变量都会自动成为对象的句柄。在 C++ 中,您可以将句柄和实际对象都存储在变量中,因此您需要告诉编译器您打算何时拥有句柄以及使用哪种类型。

于 2013-03-15T17:52:48.237 回答
1

1)它告诉你是因为你声明的是一个真实的对象,而不是一个指向对象的指针。动态绑定仅适用于指向对象的指针。

让我们看看这个:

IShape cShape = IShape();
Triangle cTriangle = Triangle();

两者在语法上都是正确的,您正在声明具有正确类型的对象。但是你不能实例化IShape,因为它是抽象的。

IShape pShape = Triangle();

Syntactically correct but since pShape is concrete, the space for it is already reserved on stack, this means that everything in addition to what a IShape already is will be discarded and this ends up in object slicing. You can't use polymorphism with this situation.

IShape* pTriangle = new Triangle();
pTriangle->draw();
...
delete pTriangle;

Correct, you are declaring a pointer to a shape and initialize it with a dynamically allocated triangle instance. This is how it should be done and this is how it works in Java (when you just have references to objects).

3) You should never include a .cpp file indeed. You should move your Triangle class declaration from the .cpp to the .h file. Then it's your choice if to implement the body methods in the header file or create a .cpp file in which you implement Triangle draw method.

于 2013-03-15T17:56:42.703 回答