7

我现在正在从 Java 迁移到 C++,每当 Java 中的一个常用概念没有直接映射到 C++ 时,我都会遇到一些困难。例如,在 Java 中,我会执行以下操作:

Fruit GetFruit(String fruitName) {
    Fruit fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?

    return fruit;
}

当然,在 C++ 中,该Fruit fruit;语句实际上创建了一个结果。这是否意味着我必须有一个默认构造函数?这似乎不安全!如果我的默认水果逃脱了怎么办?

4

7 回答 7

10

在创建水果时,C++ 让您更加头疼。根据您的需要,您可以选择以下选项之一:

1)然后在堆栈上创建一个 Fruit 并返回一个副本(您需要一个复制构造函数),并且必须提供一些默认水果以防名称不匹配:

Fruit GetFruit(const std::string &name)
{
   if ( name == "banana" ) return Fruit("banana");
   if ( name == "apple" )  return Fruit("apple");
   return Fruit("default");
}

2)在堆上创建一个 Fruit 并注意,可能会返回空指针,还记得在某处删除这个水果,并注意它只被其所有者删除一次(并注意没有人持有指向已删除水果的指针):

Fruit* GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return NULL;
}

3)最后,使用智能指针来避免许多可能的指针问题(但要注意空指针)。此选项最接近您的 Java 编程经验:

typedef boost::shared_ptr<Fruit> FruitRef;

FruitRef GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return FruitRef();
}
于 2010-07-20T15:44:53.640 回答
8

Java 中的对象由指针表示。由于这是普遍存在的,因此指针没有特殊的符号。在 C++ 中,对象可以由自身表示,也可以由指针表示,因此有必要在它们出现时指定指针。

您的代码的 C++ 版本是:

Fruit * GetFruit(std::string fruitName) {
    Fruit * fruit = 0;
    if (fruitname == "apple") fruit = new Fruit("apple");
    else if (fruitname == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat");

    return fruit;
}

这将返回一个指向Fruit. 您将访问成员喜欢fruit->color(),而不是fruit.color()delete当你完成它时,你应该使用那个指针。

于 2010-07-20T15:37:07.670 回答
4

最直接的方法是:

Fruit GetFruit(String fruitName) {
    if(fruitName == "apple") return Fruit("apple");
    else if(fruitName == "banana") return Fruit("banana");
    else fruit = return Fruit("kumquat"); //'cause who really wants to eat a kumquat?
}

...直接映射是使用(最好是“智能”)指针:

auto_ptr<Fruit> GetFruit(String fruitName) {
    auto_ptr<Fruit> fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?
    return fruit;
}
于 2010-07-20T15:38:02.683 回答
1

要将您的示例映射到 C++,您应该使用指针。在 C++ 中,构建的对象被视为有效对象(因此,在引用时,您不能为 null)。

使用水果*水果 = 0; ...

您可以将对象默认为您需要的对象,如果没有通过测试,则默认为 0。

于 2010-07-20T15:34:46.057 回答
1

在 C++ 中有指针,它们在 Java 中是隐含的:对象(即内存中的实体)与其地址之间存在差异。在 Java 中,您需要显式创建一个对象,因为当您编写

MyClass name;

您正在为该类的对象创建引用。这意味着名称标识了一个包含真实对象地址的小内存位置。当您使用 new 构建整个房子时,它只返回分配给那个小内存位置的地址。

在 C++ 中有更好的内存控制,你有两种创建对象的方法:如果你使用语句

MyClass object;

该对象在堆栈中创建。这意味着当函数返回时,对象被销毁。请注意,对象是自动创建的,无需使用 new 运算符。如果你想让一个对象持久化堆栈销毁,你应该使用 new 操作符,它返回一个指向新创建的对象的指针:

MyClass *objectPtr = new MyClass();

* 放在类名之后,表示您要求的是相对指针类型,而不是该对象的分配。

请记住,当您不再需要该对象时,您必须清理内存,否则会出现内存泄漏:

delete objectPtr;

所以,你可以这样做:

MyClass *yourfunction(bool param) {
    if (param)
        return new MyClass(A);
    return new MyClass(B);
}

无论如何,您应该知道,指针根本不安全!让用户控制指针可能会导致糟糕的代码、糟糕的做法和许多根本不好的事情直接的例子:如果你在对象使用后忘记清理内存怎么办?)

在这种情况下,最好使用智能指针,但现在真的有太多话要说 :) 享受谷歌搜索吧!

HIH

于 2010-07-20T15:45:30.893 回答
0

Objects work somewhat differently in Java vs in C++. As you noted, in your code you would default create an object and then you run the risk of it being passed around later. To make the minimum amount of change to your code:

Fruit GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return Fruit(fruitName);
}

However this code will result in the object itself (including all of its internal data) being copied in the return, as well as if its copied around in further use.

To be more Java-esque you would use a boost::shared_ptr instead. Then you're dealing with a reference counted object, just like in Java:

boost::shared_ptr<Fruit> GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return new Fruit(fruitName);
}
于 2010-07-20T16:50:05.990 回答
0

fruit在 java 中的变量大致映射到 C++ 指针。你是对的,你不想在堆栈上创建对象,你只想要一个指向你正在创建的新对象的指针。因此,如果您只是更改FruitFruit*this 将起作用(如果您也更改了函数返回类型)。请记住,稍后您必须delete从该函数返回的指针,没有垃圾收集来清理您new的 s.

于 2010-07-20T15:36:38.957 回答