我有一个魔鬼的时间了解的参考。考虑下列代码:

class Animal
{
public:
    virtual void makeSound() {cout << "rawr" << endl;}
};

class Dog : public Animal
{
public:
    virtual void makeSound() {cout << "bark" << endl;}
};

Animal* pFunc()
{
    return new Dog();
}

Animal& rFunc()
{
    return *(new Dog());
}

Animal vFunc()
{
    return Dog();
}

int main()
{
    Animal* p = pFunc();
    p->makeSound();

    Animal& r1 = rFunc();
    r1.makeSound();

    Animal r2 = rFunc();
    r2.makeSound();

    Animal v = vFunc();
    v.makeSound();
}

结果是:"树皮树皮类别类别".

在Java的思维方式,(其显然已经破坏了我的概念化C++),结果将是"树皮树皮树皮树皮".我了解我 前一个问题 这种差异是由于切片和我现在有一个很好的理解什么切片。

但是,让我们说,我想要一个功能,返回一个动物的价值,是真的狗。

  1. 我理解正确的话,最近,我可以得到的是一个 参考?
  2. 此外,它有责任使用的rFunc界面查看,参考回是分配一个动物?(或者故意将参照一个动物,通过切,放弃多态性。)
  3. 如何在地球上,我要回一个参考的一个新产生的对象,而不是做愚蠢的事情我做了上述在rFunc?(至少我听说这是愚蠢的。)

更新:因为每个人似乎都同意,到目前为止,rFunc它非法的,这带来了另一个相关的问题:

如果我通过后一个指怎么做我通知程序的指针不是他们以删除,如果是这种情况?或者我该如何进行通信的指针是受到删除在任何时间(从相同的线,但是不同功能),以便调职能不应当储存,如果是这种情况。是唯一的方式通过意见?这似乎是马虎。

注:所有这一切都是导致一个想法,模板shared_pimpl概念我的工作。希望我会了解足以后的一些有关在一两天。

有帮助吗?

解决方案

1)如果要创建新的对象,你永远不要返回的一个参考(见你自己的评论#3.) 你可以回返的一个指(可能包裹 std::shared_ptrstd::auto_ptr).(你也可以返回通过复制,但这不符合使用 new 操作者;这也有稍微不符合多态性。)

2) rFunc 是错误的。不这样做。如果你使用 new 创建的目的,然后返回它通过一种(选择性地包裹的)的指针。

3)你不应该。那是什么样的指针。


编辑 (回复您的更新:)很难想象的方案中你描述的。它会更准确的说,返回的指针可能是无效的一次呼叫呼叫其他一些(具体的)方法?

我建议反对使用这样一个模型,但是如果你绝对必须这样做,并必须执行这在你的API,然后你可能需要增加一层,或甚至两个。例如:包裹的真正目的在引用计数的对象,其中包含实际的指针。基准计算的对象是指设定为 null 当真正的目的是删除。这是丑陋的。(可能有更好的方式来做到这一点,但他们仍然可以是丑陋的.)

其他提示

要回答第二部分的你的问题("我如何进行通信的指针是受到删除在任何时间")-

这是一个危险的做法,具有微妙的细节,你会需要考虑。这是活泼的性质。

如果指针可以删除任何时间点,它是永远不会安全使用它从另一个方面,因为即使你检查"你还是否有效?"每一次,它可以删除,只是一点点之后的检查,但在此之前得到使用。

一个安全的方式做这些东西是"弱指针"的概念-有的对象被储存作为一个共用的指针(一个级别的间接,可以在任何时间),和已经返回的价值是一个薄弱的指针的东西,你必须 查询 可以使用之前,必须释放后使用它。这种方式,只要对象仍然是有效的,可以使用它。

伪代码(基于发明了薄弱的和共同的指针,我不用提升...)-

weak< Animal > animalWeak = getAnimalThatMayDisappear();
// ...
{
    shared< Animal > animal = animalWeak.getShared();
    if ( animal )
    {
        // 'animal' is still valid, use it.
        // ...
    }
    else
    {
        // 'animal' is not valid, can't use it. It points to NULL.
        // Now what?
    }
}
// And at this point the shared pointer of 'animal' is implicitly released.

但是,这是复杂的和容易出现错误,可能会让你的生活更难。我建议你去采用较简单的设计,如果可能的。

为了避免片你已经返回,或者通过周围一个 指针 的对象。(注意这一参照基本上是一个'永久性地取消引用的指针'.

Animal r2 = rFunc();
r2.makeSound();

在这里,r2婷化(使用的编译器生成的副本构造函数),但它离开 关于狗的部分。如果你这样做的切片不会发生:

Animal& r2 = rFunc();

但是你vFunc()function片里面的方法本身。

我还会提到这一功能:

Animal& rFunc()
{
    return *(new Dog());
}

这是奇怪的和不安全;你创建的一个参照一个临时的未命名的可变(引用狗).它更适当的回的指针。返回的参考文献通常被用于返回部件的变量等。

如果我通过后一个指怎么做我通知程序的指针不是他们以删除,如果是这种情况?或者我该如何进行通信的指针是受到删除在任何时间(从相同的线,但是不同功能),以便调职能不应当储存,如果是这种情况。

如果你真不能相信的用户,然后不要给他们一个指针:通过整型手柄和公C式的界面(例如,你有一个矢量的实例在你身边的围栏,并且你让一个功能,需要整数作为第一个参数、索引入的矢量,并呼吁成员的功能)。这是老式的方法(尽管我们并不总是有花哨的东西像"成员的职能";)).

否则的话,尝试采用一个聪明的指针,以适当的语义。没有人理会没有想过, delete &*some_boost_shared_ptr; 是一个好主意。

但是,让我们说,我想要一个功能,返回一个动物的价值,是真的狗。

  1. 我理解正确的话,最近,我可以得到的是一个参考?

是的,你是正确的。但我认为问题不在这么多你不明白的参考,但是,你不了解不同类型的变量在C++或如何 new 工作C++。C++、变量可以是一个原始数据(int、浮动,双等), 一个目的,或针/参照的原始和/或对象。在Java、变量只能是一种原始的或者参考的对象。

C++,当你宣布一个可变的,实际存分配和相关的变量。在爪哇,你必须明确地创建对象的使用新的和明确分配的新的对象为一个变量。这里的关键点是,虽然,在C++、对象和变量,用于访问是不一样的事情的时候的变量是指或参考。 Animal a; 意味着不同的东西从 Animal *a; 这意味着不同的东西从 Animal &a;.没有这些具有兼容的类型,而它们是不能互换。

当你的类型, Animal a1 在C++。一个新的 Animal 目的是创建。所以,当你的类型 Animal a2 = a1;, 你有两个变量(a1a2)和两个 Animal 对象,在不同的位置存储器。这两个对象具有相同价值,但是你可以改变他们的价值观独立的,如果你想要的。在爪哇,如果你输入相同的精确的代码,你会有两个变量,但只有一个对象。只要你没有重新分配的变量,他们将永远具有同样的价值。

  1. 此外,它有责任使用的rFunc界面查看,参考回是分配一个动物?(或者故意将参照一个动物,通过切,放弃多态性。)

当你使用的参考和指针,你可以访问的一个目的价值,而不复制它,你要使用它。这可以让你改变它从外面的括号里,你宣布的对象的存在。参考文献一般都是作为功能的参数或者返回对象的私人数据成员没有作出新的副本。通常,当你接受一个参考,你不将其分配的任何东西。用你的实例,而不是分配对的参考返回的 rFunc() 以一个可变的,一个通常的类型 rFunc().makeSound();.

所以,是的,有义务用户的 rFunc(), 如果他们分配返回价值的东西,将它分配给一个参考。你可以看到为什么。如果分配的参考返回的 rFunc() 以一个可变的声明 Animal animal_variable, 你最终有一个 Animal 变量之一 Animal 目,和一个 Dog 对象。的 Animal 对象的关联 animal_variable 是,尽可能多的复印件 Dog 对象返回的参考从 rFunc().但是,你不能得到多形态的行为 animal_variable 因为这可变的不相关 Dog 对象。的 Dog 对象返回的参考依然存在,因为你创造了它,使用 new, 但它不再是访问--它被泄露。

  1. 如何在地球上,我要回一个参考的一个新产生的对象,而不是做愚蠢的事情我做了上述在rFunc?(至少我听说这是愚蠢的。)

问题是,您可以创建一个对象有三种方式。

{ // the following expressions evaluate to ...  
 Animal local;  
 // an object that will be destroyed when control exits this block  
 Animal();  
 // an unamed object that will be destroyed immediately if not bound to a reference  
 new Animal();  
 // an unamed Animal *pointer* that can't be deleted unless it is assigned to a Animal pointer variable.  
 {  
  // doing other stuff
 }  
} // <- local destroyed

所有 new 会用C++是创造物体在内存在那里不会销毁,直到你这样说。但是,为了破坏它,你要记住它是建立在记忆。你做的是,通过创建一个指可变的, Animal *AnimalPointer;, 和分配的指返回的 new Animal() 它, AnimalPointer = new Animal();.摧毁 Animal 对象当你用它做的,你要类型 delete AnimalPointer;.

第1点:不要使用的参考。使用的指针。

第2点:你有上述被称为分类是分层次的分类方案。分类的范例中的一种,这是完全不适合面向对象的模型。你简单的例子仅因为你的基地的动物承担所有的动物弄出声音,和不能做什么有趣的。

如果你试图实施相关的,例如

虚拟bool动物::吃(动物*其他)=0;

你会找到你不能这样做。事情是:狗不是一个子类型的动物抽象概念。整点的分类法是这一类中的每个水平分区有一个新的有趣的性质。

例如:脊椎动物有一个骨干,我们可以询问它是否是由cartiledge或骨..我们甚至不能问这个问题的无脊椎动物。

完全明白,你必须看到,你不能让一个狗的对象。毕竟,这是一个抽象的概念,对吗?因为,还有凯尔派和牧羊犬,和一个单独的狗必须的某些物种的..这类方案可以作为深为你喜欢,但它不能支持任何具体的个人。菲是 没有一只狗, 那只是他的分类标签。

(我忽略你的问题与动态存储器进入引用导致记忆的泄露...)

你的分裂问题消失的时候动物是一个抽象的基类。这意味着它具有至少一个纯粹的虚拟的方法和不可直接实例化。下面变成一个编译器的错误:

Animal a = rFunc();   // a cannot be directly instantiated
                      // spliting prevented by compiler!

但compiler允许:

Animal* a = pFunc();  // polymorphism maintained!
Animal& a = rFunc();  // polymorphism maintained!

因此编译器节省了一天!

如果你想要返回多形式,从一个方法并不希望将其分配堆上你可以考虑使这一领域在于方法的类和使的功能返回一个指向它的任何基类你想要的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top