关于来自c#开发人员的c ++的一些问题

时间:2012-02-21 09:31:20

标签: c++

我对c#开发人员的c ++有一些疑问。

因为几天我正在查看一些c ++代码,并且我有以下问题:

  1. 何时使用Foo::Foo.Foo->
  2. 我何时使用真正的构造函数,何时只使用String a;(有时我需要像String a("foo");那样做。)
  3. 这些签名之间的区别在哪里:int foo(int a)int foo(int &a)

5 个答案:

答案 0 :(得分:5)

::用于显式指定名称空间(std::string,例如,对于名称空间std中的字符串类),或者用于类的静态成员。

.与C#一样,用于引用类的成员。

->与指针一起使用。如果p是指向对象obj的指针,则p->xobj.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:假设你要调用哪个方法

  

富:: theMethod(...)

例如,在调用类Foo

的静态方法时使用

  

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的方法 StringString必须具有可访问的复制构造函数。

在其他情况下,例如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)

  1. String a:构造一个空的String对象

    String a("foo"):构建String <{1}}

  2. "foo"个对象
  3. int foo(int a):将值{/ 1}传递给foo。如果您修改a,foo内部将不会受到foo外的影响

    a:在foo中通过引用传递a。如果您修改int foo(int& a),{fn}结束后也会修改a

答案 4 :(得分:0)

  1. Foo:: - 静态方法

    Foo. - 具有堆栈对象实例的实例方法。 (MyObject obj

    Foo-> - 有对象指针时的实例方法。 (MyObject* pObj = new MyObject()

  2. 每当您需要将一些值传递给构造函数时。

  3. int&是对int的引用。方法中对 a 的任何更改都会影响方法外的 a 。 (相当于C#中的ref