Motivation for C++ class pointers
我是C ++的新手,我对C和不同的动态脚本语言有一点经验,比如JavaScript,PHP和一些Ruby和Python。我已经使用面向对象(OO)原则工作,即使不是很长时间,但对我来说,新的事情是C ++确实使用了指向类的指针。 C中的指针对我来说不再是一个谜(至少我希望如此)如果我做对了 - 除非你没有别的选择,否则永远不要使用指针。例外情况是,如果要跟踪特殊变量,或者想要将其传递给函数以更改其值。因为我必须有动力使用指针,我可以在C ++中使用它们。你能参考一个例子吗?我在维基百科上学习过。它是C ++中Builder Design Pattern的一个例子。它们使用Pizza class和PizzaBuilder,它使用m_pizza指向Pizza类的指针。在这里使用指针而不是普通实例的原因是什么?
编辑:
只是为了避免误解
-
"C中的指针对我来说不再是一个谜(我希望至少如此),如果我做对了 - 除非你没有别的选择,否则不要使用指针"我担心你弄错了 - 我想你怎么能做任何严肃的事C中的软件,不使用指针。只要您需要使用动态内存(malloc),就必须使用指针。在C ++中,您可以使用标准库容器减少显式动态内存管理,但只要您使用new分配其中一个,就必须处理指针。
-
C ++中没有"类指针",因为C ++类不是对象。但是有对象指针。那是你指的是什么?
-
让我补充一点,你可能还没有真正掌握面向对象编程(OOP)的原理。因为在OOP中,对象需要彼此通信,经常与他们自己不创建的对象进行通信。并且指向这些对象的指针是唯一的方法。甚至像Java这样的语言也一直使用指针,即使它们试图将它们隐藏在引擎盖下。实际上,C ++在实际上允许你创建非动态分配对象的方式上是独一无二的;但即使对于这些实例,方法调用也隐含地传递了这个指针!
-
@LorenzoDonati我从来没有说我创造了任何严肃的软件,但我愿意这就是为什么我在学习。我从未学过编程,到目前为止我学到的一切都是我自学的。也许我说错了说我不再是一个谜,我真正的意思是我理解指针存储在内存中的方式。我得到它如何在C中工作,如上所述,我甚至可以模拟OOP,指针存储所有需要的代码的参考,我的意思是根据示例为什么它在那里使用?我不能只使用正常的班级???
-
对指针的充分理解是使用C ++的基础。一个很好的起点可能是获得这个问题中列出的一本入门C ++书籍。
-
@cmaster非常有趣。正如我所说,我遇到的唯一OOP语言是脚本语言。我看到了使用类作为以人类可读且易于使用的方式存储大量代码的方式的原因。我认为指向相同的内存位置更有效但不是它反对多态?您有多个具有不同属性值的实例?如果有可能我怎么能用这种方式指针。提前致谢:)
-
@EJP Ooo,是的,你的确是对的,这就是我的意思。使用它的动机是什么?
-
请记住,尽管OOP的一般原则在应用于不同语言时没有那么不同,但细节和特定习惯用语可能大不相同(我不仅仅是语法,而是语义)。与脚本语言相比,C ++尤其如此。我的建议是,在尝试将一般抽象概念理解为使用C ++作为基础的设计模式之前,您应该很好地掌握C ++的基础知识。
-
此外,尽量不要将自己与C混淆:大多数人认为C ++或多或少是C的超集,但事实并非如此。即使基本的东西在C和C ++之间也可能不同。常见的语法可能会隐藏不知情的令人讨厌的意外。如果你想学习C ++,请不要将它与C混合,直到你获得更多的经验。
-
@LorenzoDonati感谢您的建议,但我认为最好的学习方法是采取行动:),我不会创建任何可用于真实项目的代码来伤害任何人。但是我有什么优势可以跟踪那个比萨级?如果只需要数据(方法等),为什么要创建其他指针?或者我读错了代码。正如我已经说过的那样,我是C++的新手,有可能我弄错了......
-
关于你指针反对多态的评论:如果你没有指针,你和编译器就知道对象的确切类型,因此甚至不需要运行时决策。关于多态性的观点是,您可以将实例称为它的超类的实例,并且在运行时将方法调用分派给正确的类。这通常需要使用指针,否则你将永远不会遇到在编译时你不知道实例的确切类的情况。
-
@LorenzoDonati对于学习OOP,C ++是最糟糕的语言之一。首先,由于其令人难以置信的复杂性及其许多技术细节,其次,因为如此多的代码通过模板使用编译时决策(这与OOP无关)。我真正学习OOP的最佳语言是ObjectiveC。
-
@cmaster我完全同意你的观点,认为C ++是学习OOP的不错选择。我不了解Objective-C,但根据我过去的经验,我会建议Java:它很强大,很多很好的文档也针对初学者,很多安全网,很多"正常工作"的库。唉,我承认写作和阅读相当冗长而且没有太多乐趣:-),但一个好的IDE有助于那里。啊,当然不是更快的马(但初学者不应该在意)。
-
@LorenzoDonati ObjectiveC的主要特征是动态类型化,所有方法调用都在运行时调度。您有静态类型,但它们仅用于错误检查。这让人觉得它应该是一种OO语言。你也有内置的引用计数,你可以像这样编写方法调用:[myDictionary setObject:someObject forKey:@"key"] - 几乎没有比ObjectiveC代码更可读的东西。使用语言真的非常灵活,非常明确,非常有趣。可惜,它只是苹果公司:-(
他们在这个例子中使用指针的原因是它是一个抽象工厂。
其目的是从不同的披萨类中制作披萨制品。
抽象工厂需要保存这些对象而不知道它们在内存中占用了多少空间。这就是为什么你不能在这里使用普通实例作为成员变量。它们的大小因披萨制造商的每个实施而不同。
嗯,我认为这就是这里的想法。在这个例子中,他们总是使用相同的比萨类,但你可以通过从基础比萨饼中获得一个可以生产具有完全不同特征的比萨饼的工厂。然后你需要在抽象披萨生成器中使用指针来抓住披萨。
-
那么,抽象类是否在内存中引用了相同的Pizza?这就是他们如果使用普通实例就会占用额外空间的方式,到目前为止我是否正确?因此,每次实现新的抽象类时,它们最终都会重写Pizza指针所指的内存位置,对吧? constructPizza方法确保内存位置具有新的PizzaBuilder实现的新属性值?我对吗?
-
抽象类是无法实例化的基类。它们至少有一个纯虚方法(将它们想象为需要在具体派生类中实现的签名)。请记住,每个派生类也都是抽象类型"Pizza",因此无论派生类是什么(向上转换),您都可以给出指向这些对象的Pizza指针。如果派生类是多态的,这很有用。关于多态,请参阅wiki:en.wikipedia.org/wiki/Polymorphism_%28computer_science%29
-
好吧,关键是你可以创造不同种类(派生类)的比萨饼。想象一下有馅料和馅料的披萨。你需要至少一个额外的成员才能在披萨派生的FilledPizza中保持顶部。抽象工厂也可以拿着披萨,即使它不是"标准"披萨对象。但是填充的披萨与标准披萨的尺寸不同。这就是它在堆上分配并用指针存储的原因。我想我无法解释它更好。还有谁?
-
当你写关于抽象工厂的@dsu你的意思是建造者吗?我对抽象工厂并不熟悉,我不知道它与建筑类的区别。我关心的是记忆。我不得不再次向你道歉,但他们是否在PizzaBuilder中使用指向披萨的指针,以便所有派生类如Hawaiian-和SpicyPizzaBuilder指向同一个对象?在这种情况下,派生类的每个实现都会覆盖以前的值..?
-
@orustammanapov请阅读并搜索设计模式。有关更多信息,请参阅此处:en.wikipedia.org/wiki/Software_design_pattern - Factory是一种用于创建对象的设计模式,而不指定将创建对象的确切类类型。在此处查看更多信息:en.wikipedia.org/wiki/Factory_method_pattern
-
@NickL伙计们,我非常感谢你的帮助,但每次得到评论我都会感到沮丧,因为我觉得没有人读我写的东西。我不想更加困惑,我有一个关于记忆的问题,并且关于一种方式比另一种更好,如果设计模式适用于我所指的例子,那么设计模式是任何关注的。示例是关于构建器模式,那么抽象工厂模式如何与我的问题相关,如果可能的话请尽量避免混合可能被删除或解释不同的东西。并感谢链接。
-
@orustammanapov我为误解你的问题而道歉,我会尽力回答有关记忆的问题。"m_pizza =新比萨饼";分配内存并使指针成员变量"m_pizza"指向它。通过使用getPizza(),您将获得指向对象的已分配内存的指针。请注意,如果我们在此处有两个相同构建器实例createNewPizzaProduct()的后续调用,则将创建2个对象,但只有最后一个内存将被设置为由成员变量指针指向,从而导致内存泄漏。不同的构建者也将值放在他们自己的m_pizza var上。实例。
-
另外,关于Builder和Factory的区别,请看这里:stackoverflow.com/questions/757743/
-
@NickL。 很好的回答,谢谢! 你确定内存泄漏吗? 通过调用cook.getPizza()程序员返回Pizza指针(后来删除它),并且在下一次createNewPizzaProduct()调用之前执行它,指针是否存储在夏威夷和辣变量中? 我可能会弄错,只是好奇.. :)并且可以把它写成答案,所以我可以接受它。 再次感谢。
-
在示例中调用它的方式不会导致内存泄漏。 但是,例如,他打电话给m_pizzaBuilder-> createNewPizzaProduct(); 在Cook的constructPizza()类中2次(例如可能是一个错误),可能会有一个。 我的观点并不是代码被泄露(我认为它不会,在这个例子中),但它不能保证可能的内存泄漏。
-
好的,张贴回答,谢谢。
m_pizza =新比萨饼; constructPizza()方法中的行分配内存并使指针成员变量"m_pizza"指向它。通过使用getPizza(),您将获得指向对象的已分配内存的指针。
除此之外,创建的每个构建器对象都有自己的Pizza指针成员变量。因此,在主要的,每个getPizza()调用后,夏威夷和辣指向的Pizza对象都是不同的对象。
另外,请注意,如果我们在某处有2个相同构建器实例createNewPizzaProduct()的后续调用,则会创建2个对象,但只有最后一个内存将被设置为由成员变量指针指向,从而导致内存泄漏。 (例如,如果m_pizzaBuilder-> createNewPizzaProduct();在Cook的constructPizza()方法中被错误地调用了2次,可能会发生这种情况。我的观点是这里的代码可能更安全,但它似乎没有任何内存泄漏泄漏了它的写法)。