我对c#开发人员的c ++有一些疑问。
因为几天我正在查看一些c ++代码,并且我有以下问题:
Foo::
,Foo.
和Foo->
?String a;
(有时我需要像String a("foo");
那样做。)int foo(int a)
和int foo(int &a)
?答案 0 :(得分:5)
::
用于显式指定名称空间(std::string
,例如,对于名称空间std
中的字符串类),或者用于类的静态成员。
.
与C#一样,用于引用类的成员。
->
与指针一起使用。如果p
是指向对象obj
的指针,则p->x
与obj.x
的含义相同。
何时使用真正的构造函数,何时只使用String a; (有时候我需要做一些像String a(“foo”);)
当你需要时。 String a
大致相当于C#的a = new String()
(如果String
是非POD类型,则可能包含未初始化的成员。)
如果您需要将a
初始化为特定值,则可以执行此操作。 (使用String a("foo")
或使用String a = "foo"
)
这些签名之间的区别在哪里:int foo(int a)和int foo(int& a)?
&
表示参考。它不是相当 C#引用,但有相似之处。在C#中,您有值类型和引用类型,引用类型总是通过引用传递。
在C ++中,没有这样的区别。每种类型都可以通过值或引用传递。类型T&
是对的引用。换句话说,给出以下代码:
void foo(int& j);
void bar(int j);
int i = 42;
foo(i);
bar(i);
foo
会向<{1}}提供引用,这意味着它可以修改i
的值。
i
将获得 bar
的副本,这意味着它所做的任何修改都不会反映在i
中。
您经常使用i
(对const T&
的引用)作为避免复制的方法,同时仍然阻止被调用者修改对象。
答案 1 :(得分:2)
1:假设你要调用哪个方法
例如,在调用类Foo 的静态方法时使用富:: theMethod(...)
Foo.theMethod(...)
是指有一个名为Foo的对象
Foo-&GT; theMethod(...)
是指向一个名为Foo
的对象的指针2:
字符串a;
调用不带参数的默认构造函数
字符串a(“foo”)
调用重载的构造函数
3:
int foo(int&amp; a)
引用一个整数,因此在该方法中你可以操作一个。
int foo(int a)
制作副本,操纵它不会对离开方法后传入的实际参数产生任何影响。
答案 2 :(得分:2)
问题1:
这取决于Foo
是什么。 ::
运算符称为范围
分辨算子;右边的操作数必须是命名空间或
class,左边的操作数是命名空间或类的成员。
如果Foo
是一个类,Foo::
可用于访问静态成员,或
从派生类的成员中,访问该成员
基类:例如:
class Foo
{
public:
virtual void f();
static void g();
};
int h()
{
Foo::g();
}
class Derived : public Foo
{
public:
virtual void f()
{
Foo::f(); // Call function in base class...
}
}
它通常也用于访问命名空间成员,例如std::cout
(名称空间cout
中的std
对象。)
.
运算符是成员访问运算符,需要一个对象(或
对象的引用)作为左手操作数。因此(使用
以上定义):
Foo obj;
obj.f();
void i( Foo& rFoo )
{
rFoo.f();
}
如果你有一个实例,它也可以用来访问静态成员:
Foo obj;
obj.g();
->
与.
运算符非常相似,只需要一个
指向实例的指针,而不是实例,并且(非常重要)
它可以超载。因此:
Foo* obj;
obj->g();
// And if Ptr is a user defined type with an overloaded
// `operator->` which returns a Foo*
Ptr obj;
obj->g();
同样,如果您也可以使用此语法来访问静态成员 有一个指向对象的指针。
问题2:
定义String a;
调用一个真正的构造函数。如果需要默认构造函数,可以使用String
a;
;没有参数的那个。
如果需要构造函数,则使用String a( "foo" );
char const*
(或char const (&)[4]
,但这是非常不可能的,因为它
只适用于具有三个字符的字符串文字。)
通常,在定义变量时:
String a; // default constructor...
String a1(); // NOT what it looks like: this is a
// function declaration, and not the
// definition of a variable!!!
String b( x, y, z ); // constructor taking x, y and z as arguments...
String c = x; // implicitly convert `x` to String, then
// copy constructor.
最后一种形式有点棘手,因为复制构造函数可能是(和
几乎总是被淘汰,但程序的合法性是由
上面的规则:必须有一种隐式将x
转换为a的方法
String
和String
必须具有可访问的复制构造函数。
在其他情况下,例如new String()
,带有空参数的表单
可用于“值构造”,这是默认构造函数
如果有用户定义的,则初始化为零。
问题3:
第一个是按值传递,并将参数的副本传递给 功能。第二个是通过引用传递,并传递引用 (其行为有点像隐藏,自动解除引用 指针)到函数。因此:
void f( int a )
{
++ a; // Modifies local copy, has no effect on the argument.
}
void g( int& a )
{
++ a; // Modifies the variable passed as an argument.
}
请注意,在第一种情况下,您可以传递任意表达式;在 第二,你必须通过一个称为左值的东西 - 也就是说, 你可以使用类似的表达式(命名的 变量,或dererenced指针,或命名数组中的元素, 等)。
答案 3 :(得分:1)
String a
:构造一个空的String
对象
String a("foo")
:构建String
<{1}}
"foo"
个对象
int foo(int a)
:将值{/ 1}传递给foo。如果您修改a
,foo内部将不会受到foo外的影响
a
:在foo中通过引用传递a
。如果您修改int foo(int& a)
,{fn}结束后也会修改a
答案 4 :(得分:0)
Foo::
- 静态方法
Foo.
- 具有堆栈对象实例的实例方法。 (MyObject obj
)
Foo->
- 有对象指针时的实例方法。 (MyObject* pObj = new MyObject()
)
每当您需要将一些值传递给构造函数时。
int&
是对int
的引用。方法中对 a
的任何更改都会影响方法外的 a
。 (相当于C#中的ref
)