编辑:这个问题更多的是关于语言工程而不是C++本身.我以C++为例来展示我想要的东西,主要是因为我每天都在使用它.我并不想知道它是如何工作的C++,但打开它如何的讨论会来完成.
这不是它现在的工作方式,这就是我希望它可以完成的方式,这肯定会打破C兼容性,但这就是我认为extern"C"的全部意义.
我的意思是,在您现在声明的每个函数或方法中,您必须显式写入该对象将通过引用在其上添加前缀作为参考运算符.我希望每个非POD类型都会通过引用自动发送,因为我使用了很多,实际上对于每个大小超过32位的对象,这几乎是我的每一类.
让我们举例说明它是如何做的,假设a,b和c为类:
class example { public: int just_use_a(const a &object); int use_and_mess_with_b(b &object); void do_nothing_on_c(c object); };
现在我想要的是:
class example { public: int just_use_a(const a object); int use_and_mess_with_b(b object); extern "C" void do_nothing_on_c(c object); };
现在,do_nothing_on_c()的行为就像今天一样.
至少对我来说这会很有趣,感觉更清楚,而且如果你知道每个非POD参数都是通过引用而来的,我相信如果你必须明确地声明它,那么错误将是相同的.
对于这种变化的另一种观点,来自C的人,参考运算符在我看来是一种获取变量地址的方法,这就是我用来获取指针的方式.我的意思是,它是相同的运算符,但在不同的上下文中具有不同的语义,对你来说这不是觉得有点不对吗?
我猜你错过了C++和C++语义的观点.你错过了C++在传递(几乎)所有东西时是正确的事实,因为它是在C中完成的.总是.但不仅仅是在C中,我将在下面向您展示......
在C中,一切都按值传递.通过复制它们的值来传递"原语"和"POD".在您的函数中修改它们,原始文件将不会被修改.尽管如此,复制一些POD的成本可能并非琐碎.
当您使用指针表示法(*)时,您不会通过引用传递.你传递了一份地址副本.哪个或多或少相同,只有一个微妙的区别:
typedef struct { int value ; } P ; /* p is a pointer to P */ void doSomethingElse(P * p) { p->value = 32 ; p = malloc(sizeof(P)) ; /* Don't bother with the leak */ p->value = 45 ; } void doSomething() { P * p = malloc(sizeof(P)) ; p->value = 25 ; doSomethingElse(p) ; int i = p->value ; /* Value of p ? 25 ? 32 ? 42 ? */ }
p->值的最终值为32.因为p是通过复制地址的值来传递的.因此原始的p没有被修改(并且新的p被泄露).
对某些人来说这可能是令人惊讶的,但在Java中,一切都是按价值复制的.上面的C示例将在Java中给出完全相同的结果.这几乎就是你想要的,但是你不能像在C中一样容易地传递原语"by reference/pointer".
在C#中,他们添加了"ref"关键字.它或多或少像C++中的引用一样.关键是,在C#上,你必须在函数声明和每次调用中都提到它.我想这不是你想要的,再次.
在C++中,几乎所有东西都是通过复制值传递的.当你只使用符号的类型时,你正在复制符号(就像在C中完成一样).这就是为什么当你使用*时,你传递的是符号地址的副本.
但是当你使用&时,假设你正在传递真实对象(无论是struct,int,pointer,等等):引用.
很容易将它误认为是语法糖(即,在幕后,它像指针一样工作,并且生成的代码与指针一样).但...
事实是,参考不仅仅是语法糖.
与指针不同,它授权像在堆栈上一样操纵对象.
取消指针时,与const关键字相关联,它授权从一种类型到另一种类型的隐式提升(主要通过构造函数).
与指针不同,符号不应该为NULL /无效.
与"副本"不同,您不会花费无用的时间来复制对象
与"副本"不同,您可以将其用作[out]参数
与"副本"不同,您可以在C++中使用全范围的OOP(即将完整对象传递给等待接口的函数).
因此,参考文献具有两全其美的优点.
让我们看一下C示例,但在doSomethingElse函数上有一个C++变体:
struct P { int value ; } ; // p is a reference to a pointer to P void doSomethingElse(P * & p) { p->value = 32 ; p = (P *) malloc(sizeof(P)) ; // Don't bother with the leak p->value = 45 ; } void doSomething() { P * p = (P *) malloc(sizeof(P)) ; p->value = 25 ; doSomethingElse(p) ; int i = p->value ; // Value of p ? 25 ? 32 ? 42 ? }
结果是42,旧p被泄露,取而代之的是新p.因为,与C代码不同,我们不会传递指针的副本,而是传递指针的引用,即指针本身.
使用C++时,上面的例子必须清楚明了.如果不是,那么你就错过了什么.
C++是pass-by-copy/value,因为它是一切正常的方式,无论是在C语言,C#还是在Java中(即使在JavaScript ... :-p ...中).和C#一样,C++有一个引用运算符/关键字作为奖励.
现在,就我所理解的而言,你可能正在做我称之为半开玩笑的C +,即具有一些有限的C++特性的C语言.
也许你的解决方案是使用typedef(它会激怒你的C++同事,看看被无用的typedef污染的代码......),但这样做只会混淆你真正缺少C++的事实.
正如在另一篇文章中所说,你应该将你的思维方式从C开发(无论如何)转变为C++开发,或者你应该转向另一种语言.但是不要继续用C++函数编写C语言编程,因为通过有意识地忽略/混淆你使用的习语的力量,你将产生次优的代码.
注意:除了原语外,不要复制任何其他内容.你将从它的OO容量中阉割你的函数,而在C++中,这不是你想要的.
这个问题有所修改(参见/sf/ask/17360801/).我让我的原始答案,并回答下面的新问题.
您如何看待C++上的默认传递引用语义?就像你说的那样,它会破坏兼容性,并且你将对原语(即内置类型,仍将通过副本传递)和结构/对象(将作为引用传递)进行不同的传递.你必须添加另一个运算符来表示"按值传递"(extern"C"非常糟糕,已经用于其他完全不同的东西).不,我真的很喜欢今天用C++完成它的方式.
[...]参考运算符在我看来是一种获取变量地址的方法,这就是我用来获取指针的方式.我的意思是,它是相同的运算符,但在不同的上下文中具有不同的语义,对你来说这不是觉得有点不对吗?是的,不是.当与C++流一起使用时,运算符>>改变了它的语义.然后,您可以使用operator + =来替换strcat.我猜运算符已被使用,因为它的意思是"与指针相反",并且因为它们不想使用另一个符号(ASCII是有限的,并且范围运算符::以及指针 - >显示其他几个符号是可用的).但是现在,如果&困扰你,&&会真的让你感到不安,因为他们在C++ 0x中添加了一元&(一种超级引用......).我自己还没有消化它......
一个完全改变代码段意义的编译器选项对我来说听起来真是个坏主意.要么使用C++语法,要么找到不同的语言.