(初学者)c++构造函数和方法的继承,使用一个Java示例作为起点
(beginner) C++ inheritance in constructor and methods using a Java example as starting point
我正在学习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++主程序中有错误。因为我有几个问题,我将试着列举它们:
- 它告诉我,"mySHape"是抽象的,当它不是因为我实现它在三角形类!
- 我不能调用"mysshape .draw()",即使我修复了第一个错误
- 我的朋友说我不应该包含cpp文件。但是如果我不包含三角形,我的Main.cpp如何知道它的存在?
- 有更好的方法来移植这个例子在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();
其他问题:- 缺少析构函数实现。给
- 受保护的数据可能导致代码混乱。你应该考虑将
max_size
设为私有。 - 使用构造函数初始化列表来初始化数据成员,而不是在构造函数体中给它们赋值:
Triangle() : max_size(255) {}
.
~IShape()
一个空体,这样派生类就不会在不需要析构函数的时候强制实现析构函数。- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- 为什么像C++和Java这样的语言有一个内置的LinkedList数据结构
- 使用 CMake 和 Maven 构建C++和 Java 代码,并捆绑在一个罐子里
- 我正在尝试修改一个字节数组并通过 JNI 将其从 c++ 发送到 java
- 为什么这会在Java中给我一个ClasscastException,而它在C 中效果很好
- Java加载DLL,该DLL从JNI中的另一个DLL导出方法
- 在使用 bazel 构建一个简单的应用程序时,得到错误在 '/usr/lib/java/jdk1.8.0_74/bin/java' 找不到 java
- 从 c++ 库中获取一个字符串,周围有一个 java 包装器
- 我可以创建一个JNI调用以提升从Java的C 光纤
- 如何在Java中包含一个库,该库在C 中具有Java中具有本机绑定(库)的库
- 如何在 Java 中声明一个uint8_t数组
- 字符串在从Android Java调用ndk c ++函数后会得到一个奇怪的形式
- 在Java中使用一个或更多单词搜索整个数据库
- 如何识别一个进程是 java 还是 Linux 中的 c 或 c++ 进程
- 在java中将两个字节(一个正字节和另一个负字节)合并为短字节
- 为什么Java可以有很多Main,你可以决定要运行哪个Java文件,但对于C++来说,你只是一个Main文件
- 用C++为java构建一个dll,它正在调用另一个dll(Eclipse上的JNI)
- Java和SWIG:类集成到一个包中
- 类到另一个类的实例化:Java到C++的转换
- 从Java到C++:如何在另一个自定义类中使用一个自定义类名var