当我为我的类创建构造函数时,C ++迫使我做两件事:
我的问题是,为什么会这样?我来自Java背景,它不像Java那样,所以我想这里有一个优势,我无法看到。有人可以为我澄清一下吗?我为新手问题道歉。
// classes example
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
Rectangle(int w,int h) {
width = w;
height = h;
}
};
int main () {
Rectangle* rect = new Rectangle(5,8);
cout << "area: " << rect -> area();
return 0;
}
// classes example
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
int main () {
Rectangle rect;
rect.set_values (3,4);
cout << "area: " << rect.area();
return 0;
}
答案 0 :(得分:2)
在用于访问类成员的表示法中,C ++和Java之间存在一些相似之处:
C ++的SELECT *, min(okd.position) FROM
-- all deals
(SELECT * FROM "Deals" as d
WHERE (d.active = true) AND (d.latitude BETWEEN 40 AND 41) AND (d.longitude BETWEEN -75 AND -70)) AS okd
LEFT JOIN
-- used deals
(SELECT * FROM "Deals" as ad INNER JOIN
(SELECT * FROM "DealsUsed" AS du WHERE du."CustomerId" = 1) AS rd
ON rd."DealId" = ad.id) as dd
--deals that were not used, grouped by user and sorted by position
ON dd."UserId" = okd."UserId" AND dd.position = okd.position
WHERE dd.id IS NULL
GROUP BY okd."UserId";
通常等同于a->b
。我通常说,因为在C ++中可以重载指向成员运算符(*a).b
的指针,而不能重载->
(尽管C ++标准中有一些变动)委员会放松一下。)
至于类实例的创建,C ++中出现了复杂性,因为与Java不同,您基本上有两种关于类(和普通旧数据)类型实例化的选择。你可以使用
自动存储时间:.
动态存储时间:Rectangle rect(1, 2);
(其他几个选择 - Rectangle* rect = new Rectangle(1, 2);
和static
有更多的第一种口味。)
请注意,在C ++中,与Java不同,您需要调用thread_local
free 与{em>指针相关联的内存{{ 1}}。 C ++中的一些类(例如delete
)在管理内存方面有很大帮助。
答案 1 :(得分:2)
您不必仅因为您的班级中有构造函数而使用指针。这两件事是无关的。
的例子
Rectangle* rect = new Rectangle(5,8);
可以很容易地在没有指针的情况下重写:
Rectangle rect(5,8);
另请注意,Rectangle rect;
仍然会调用构造函数:默认构造函数(不带参数),Rectangle::Rectangle()
。如果您自己没有定义构造函数,编译器将为您生成默认构造函数。
答案 2 :(得分:0)
Java和C ++之间的主要区别(无论如何重要)是内存管理。
在第一次近似中,在Java中,所有内容都是在堆上分配的对象,并且您可以通过引用访问这些对象(尽管它们更像C ++指针而不是C ++引用,有时您可能会看到它们被称为指针)。例外是int等基本类型,这就是为什么你不能创建ArrayList<int>
的原因。系统使用垃圾收集管理对象的生命周期;当没有任何东西能够引用某个物体时,就会收集它。
C ++为您提供更多选择。一种选择是您可以使用new
关键字在堆上分配对象并通过指针访问这些对象。到目前为止,这与Java完全相同,这可能是Java借用new
关键字的原因。这里的主要区别是C ++没有跟踪这些对象的生命周期;当您希望销毁对象时,必须手动使用delete
关键字。
或者,您可以在堆栈上进行分配,如下所示:
int main () {
Rectangle rect(5,8);
cout << "area: " << rect.area();
return 0;
}
请注意,这确实使用了构造函数!在这种情况下,该rect对象的内存不在堆上,它在堆栈上。在某些方面,它现在更像是像int这样的原始类型;它的存在只要它的范围。有些人会使用术语&#34;值语义&#34;描述这样的事情。当它超出范围时,对象就会被破坏。
与堆相比,使用堆栈有一些优点和缺点。一个是在堆栈上分配内存比在堆上分配内存要快得多(在堆栈上分配内存几乎是通过增加一个指针来完成的!);另一个是堆栈对象的生命周期是完全明显的。缺点是堆栈具有相对少量的可用内存;如果你试图在堆栈上分配太多,那么你就有可能...... 溢出你的堆栈。
在这里标记的一个关键是C ++与Java的不同之处在于,在Java中,当一个对象被销毁时,由垃圾收集器决定。从程序的角度来看,它是非确定性的。这不是C ++的情况;当对象退出作用域(对于堆栈分配的对象)或者它们被显式删除(对于堆上的对象)时,对象将被销毁。所以这就是为什么C ++有了析构函数是有道理的,因为你知道它们什么时候被调用。
这就是为什么C ++没有像Java的try-with-resources / AutoCloseable(或者就此而言,C#中的IDisposable)这样的东西;析构函数扮演了这个角色。例如,如果您使用std::ifstream
从文件中读取,并在堆栈上创建该对象,则当ifstream
超出范围时,将关闭该文件,这是正确的适用于任何范围;你不需要像try-with-resources这样的特殊语法。
现在,C ++中的典型做法是使用在堆栈上分配的东西(带有值语义)来提供抽象来帮助您进行内存管理。这样的示例包括std :: vector&lt;&gt;和std :: unique_ptr&lt;&gt ;.使用具有C ++值语义的对象来管理其他资源(如内存,打开文件,互斥锁上的锁等)的生命周期的模式称为RAII。
因此,简而言之,不同之处在于C ++有两种不同的方式来分配具有真正不同语义的对象(值/堆栈和引用/堆)。 Java(大多数)只有一个(引用/堆)。尽管它们都有.
运算符,但Java .
运算符的行为类似于C ++ ->
运算符,因为它们通过指针(C ++)或引用访问其他位置的对象的字段(JAVA)。如果你尝试在空指针上使用->
,或者在空Java引用上使用.
,它们实际上可以以类似的方式爆炸。
C ++ .
运算符访问值字段。它做了不同的事情,这就是它与众不同的原因。