C ++:创建一个未初始化的占位符变量而不是默认对象

时间:2010-07-20 15:31:59

标签: c++ default-constructor

我现在正从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;语句实际上创造了一个结果。这是否意味着我必须有一个默认的构造函数?这似乎不安全!如果我的默认水果逃脱了怎么办?

7 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:7)

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指针。

答案 2 :(得分:3)

最直接的方式是:

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;
}

答案 3 :(得分:1)

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

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

你可以根据需要设置一个对象,如果没有测试通过则默认为0。

答案 4 :(得分:1)

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

MyClass name;

您正在为该类的对象创建引用。这意味着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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

对象在Java和C ++中的工作方式略有不同。正如您所指出的,在您的代码中,您将默认创建一个对象,然后您冒着以后传递它的风险。要对代码进行最小量的更改:

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

但是,此代码将导致对象本身(包括其所有内部数据)在返回中被复制,以及如果将其复制以供进一步使用。

要使用Java-esque,您可以使用boost::shared_ptr代替。然后你正在处理一个引用计数对象,就像在Java中一样:

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