(初学者)c++构造函数和方法的继承,使用一个Java示例作为起点



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

这是我的接口isshape。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++版本甚至不能编译这是我的isshape .h c++文件。它应该类似于isshape .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++ main:

#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. 我不能调用"mysshape .draw()",即使我修复了第一个错误
  3. 我的朋友说我不应该包含cpp文件。但是如果我不包含三角形,我的Main.cpp如何知道它的存在?
  4. 有更好的方法来移植这个例子在c++ ?还是我太"java化"了?

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

我做错了什么,你能提供什么技巧来改进我的代码风格?此外,对不起的文字墙,我正在努力解释自己,而不是被否决。

在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() { }

这一行是你的问题:

IShape myShape = Triangle();

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

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

试试这个:

unique_ptr<IShape> myShape = new Triangle();

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

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

你需要的是一个指针。

IShape* myShape = new Triangle();

也替换:

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

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

让我们看看这个:

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

两者在语法上都是正确的,你用正确的类型声明对象。但是你不能支持IShape,因为它是抽象的。

IShape pShape = Triangle();

语法正确,但由于pShape是具体的,它的空间已经在堆栈上保留了,这意味着除了IShape已经存在的东西之外的所有东西都将被丢弃,这最终导致对象切片。在这种情况下不能使用多态性。

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

正确,你正在声明一个指向形状的指针,并使用动态分配的三角形实例初始化它。这就是它应该如何完成,这就是它在Java中的工作方式(当你只有对对象的引用时)。

3)你不应该包含一个。cpp文件。您应该将Triangle类声明从.cpp文件移动到.h文件。然后,您可以选择是在头文件中实现主体方法还是创建一个.cpp文件,在其中实现Triangle draw方法。

这一切都源于这样一个事实,即您试图在这里实例化一个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();
其他问题:

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

最新更新