在C ++中将参数传递给方法为void *

时间:2015-01-31 22:40:09

标签: c#

我正在寻找具有通用原型的抽象方法的C Sharp示例,派生的覆盖方法可以接收不同的参数结构。

来自C ++的例子

class IBase {
public:
  virtual void method(void * pParameters) = 0;
}

class CDerivedA : public IBase {
public:
  struct S_A {
    char a;
    short b;
  }
  virtual void method(void * pParameters);
}

void CDerivedA::method(void * pParameters) {
  S_A * pSa = (S_A *)pParameters;
  pSa->a
  pSa->b
}

class CDerivedB : public IBase {
public:
  struct S_B {
    long c;
    float d;
    double e;
  }
  virtual void method(void * pParameters);
}

void CDerivedB::method(void * pParameters) {
  S_B * pSb = (S_B *)pParameters;
  pSb->c
  pSb->d
  pSb->e
}

执行速度非常重要,所以我更喜欢通过引用传递。

我在C#中找到了两个实现它的选项: 1。

interface IBase {
  void method(object parameters);
}

class CDerivedA : IBase {
  void method(object parameters) {
    // cast to use the parameters
    user obj = (user)parameters;
    ...
  }
}

class CDerivedB : IBase {
  void method(object parameters) {
    // cast to use the parameters
    point obj = (point)parameters;
    ...
  }
}

2

interface IBase {
  void method(dynamic parameters);
}

class CDerivedA : IBase {
  // directly use the parameters
  void method(dynamic parameters) {
    ...
  }
}

class CDerivedB : IBase {
  // directly use the parameters
  void method(dynamic parameters) {
    ...
  }
}
女巫更好/更快?

1 个答案:

答案 0 :(得分:3)

因为C#是一种托管语言,所以没有void*这样的东西(即使在C ++中也不是一个好主意)。 C#中有两个选项:传递'对象'或使用泛型。必须将对象强制转换为适当的类型,以用作黑盒子以外的任何其他对象。泛型(功能较弱的C#版本的模板)通常是要走的路。

如果需要传递多个参数,可以使用C#Tuple(类似于C void*数组)或params对象数组(类似于C varargs)。

如果没有一个很好的例子说明为什么这会有用(如果可能的话),这看起来就像是一个糟糕的设计。

我从评论中可以看出这个话题存在很多混淆,所以让我绝对清楚: C#和C ++中的classstruct 非常不同。在C ++中,区别在于构造和对字段的公共/私有访问。在C#中,区别在于它们作为参数传递时的处理方式。

在C#中,当您声明一个类并将“类”(实际上是该类的实例)传递给函数时,您实际上是将引用传递给将类实例放入函数中。 没有办法将类实例本身传递给函数,就像在C ++中一样。与C ++不同,在C#中,您调用的函数可以修改类实例中的数据,并且调用者将看到此类更改,因为在C ++中调用了复制构造函数,并且类实例数据实际上被复制到堆栈中,但是C#,类是引用类型。

以下是一些示例,假设CclassS在两种语言中均为struct

在C ++中:

void func (C c) 
{
     c.value = true; // This change will NOT be seen by the caller because the class was passed by value
}

void func (C* c) 
{
     c->value = true; // This change WILL be seen by the caller because the class was passed by reference (pointer in this case, though the distinction is only syntactic)
     c = new C();     // This new instance will not be seen by the caller and will never be destroyed or freed
}

void func (C& c) 
{
     c.value = true; // This change WILL be seen by the caller because the class was passed by reference
}

void func (C** c) 
{
     (*c)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function
     *c = new C();       // A new instance of C WILL be seen by the caller because the pointer to the class was passed by reference (pointer)
}

void func (S s) 
{
     s.value = true; // This change will NOT be seen by the caller because the struct was passed by value
}

void func (S* s) 
{
     s->value = true; // This change WILL be seen by the caller because the struct was passed by reference (pointer)
     s = new S();     // This new instance will not be seen by the caller and will never be destroyed or freed
}

void func (S& s) 
{
     s.value = true; // This change WILL be seen by the caller because the struct was passed by reference
}

void func (S** s) 
{
     (*s)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function
     *s = new S();       // A new instance of S WILL be seen by the caller because the pointer to the struct was passed by reference (pointer)
}

在C#中:

void func (C c) 
{
     c.value = true; // This change will be seen by the caller because the class was passed by reference
}

void func (ref C c) 
{
     c.value = true;  // This change will only be seen by the caller if they kept another reference to the class instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function
     c = new C();     // A new instance of C WILL be seen by the caller because the reference to the class was passed (by reference)
}

void func (S s) 
{
     s.value = true; // This change will NOT be seen by the caller because the struct was passed by value
}

void func (ref S s) 
{
     s.value = true;  // This change will only be seen by the caller if they kept another reference to the struct instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function.  I think this would require boxing the original struct instance.
     s = new S();     // A new instance of S WILL be seen by the caller because the struct was passed by reference
}

要在C#中按值传递实际数据(不是引用/指针),数据必须声明为struct。有关详细信息,请参阅Microsoft's explanation of structs vs. classes in C#