天道酬勤,学无止境

为什么显式收益在Proc中有所作为?(Why does explicit return make a difference in a Proc?)

问题
def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

我认为return关键字在Ruby中是可选的,无论您是否要求,您总是会return ing。 鉴于此,我发现foobar具有不同的输出是令人惊讶的,这取决于fooProc f包含显式return的事实。

有人知道为什么会这样吗?

回答1

Ruby具有三个构造:

  1. 不是对象,而是由{ ... }do ... end
  2. proc是由Proc.newproc创建的Proc对象。
  3. lambda是由lambda (或Ruby 1.8中的proc )创建的Proc

Ruby具有三个从某事物返回的关键字:

  1. return终止其所在的方法或lambda。
  2. next终止其所在的块,proc或lambda。
  3. break终止产生于该块或调用其所在的proc或lambda的方法。

在lambda中,无论出于何种原因, return行为都类似于nextnextbreak被命名为他们,因为他们是最常见的类似方法使用方式each ,其中,终止该块会导致重复,将恢复与集合的下一个元素,并终止each会使你打破循环的出。


如果在foo的定义内使用return ,则即使它在块或proc内,也将从foo返回。 要从一个块返回,可以改用next关键字。
def foo
  f = Proc.new { next "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end
puts foo # prints "return from foo"
回答2

这是Proc的语义; 它不一定是所有块的语义。 我同意这有点令人困惑。 这样做是为了增加灵活性(也许部分原因是Ruby除了其实现外没有任何规范)。

该行为在Proc实现中定义。 Lambda的行为有所不同,因此,如果您希望return不会退出封闭方法,请使用lambdas 。 或者,从您的Proc省略return关键字。

这里是对Rubys闭包的深入研究。 这是一个了不起的展览。

所以:

def foo   
  f = Proc.new {
    p2 = Proc.new { return "inner proc"};
    p2.call
    return "proc"
  }
  f.call
  return "foo"
end

def foo2
  result = Proc.new{"proc"}.call
  "foo2 (proc result is: #{result})"
end

def bar
  l = lambda { return "lambda" }
  result = l.call
  return "bar (lambda result is: #{result})"
end

puts foo
# inner proc
puts foo2
# foo (proc result is: proc) 
puts bar
# bar (lambda result is: lambda) 
回答3

这样想:Proc.new只是创建一个代码块,该代码块是调用函数的一部分。 proc / lambda创建具有特殊绑定的匿名函数。 一些代码示例将帮助您:

def foo
  f = Proc.new { return "return from foo from inside Proc.new" }
  f.call # control leaves foo here
  return "return from foo" 
end

相当于

def foo
  begin
    return "return from foo from inside begin/end" }
  end

  return "return from foo" 
end

因此很明显,返回将仅从函数“ foo”返回

相比之下:

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end

等价于(忽略绑定,因为在此示例中未使用):

def unonymous_proc
  return "return from foo from inside proc"
end

def foo
  unonymous_proc()
  return "return from foo" 
end

显然,这不会从foo返回,而是继续下一条语句。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 什么时候应该显式使用`this`指针?(When should I make explicit use of the `this` pointer?)
    问题 什么时候应该在类的方法中显式编写this->member ? 回答1 通常情况下,你不就得了, this->是隐含的。 有时,名称会存在歧义,可以用来消除类成员和局部变量的歧义。 但是,这是一个完全不同的情况,其中明确要求this-> 。 考虑以下代码: template<class T> struct A { int i; }; template<class T> struct B : A<T> { int foo() { return this->i; } }; int main() { B<int> b; b.foo(); } 如果省略this-> ,则编译器将不知道如何处理i ,因为它可能存在于A所有实例中,也可能不存在。 为了告诉i确实是A<T>的成员,对于任何T ,都需要this->前缀。 注意:仍然可以使用以下命令省略this->前缀: template<class T> struct B : A<T> { using A<T>::i; // explicitly refer to a variable in the base class int foo() { return i; // i is now known to exist } }; 回答2 如果在与现有成员同名的方法中声明局部变量,则必须使用this-> var来访问类成员,而不是局部变量。
  • 为什么在没有显式return语句的情况下递归的return调用会中断堆栈?(Why does a recursed return call break out of stack without an explicit return statement?)
    问题 有人向我展示了一个示例程序来演示递归,该递归看起来似乎不起作用,但可以起作用。 逻辑很清楚,但是为什么即使没有返回递归函数调用也能正常工作呢? 即使没有要求, return命令似乎也会脱离堆栈。 这是语言标准还是gcc? 我在Windows和Linux上用gcc编译的C和C ++看到了它。 #include <iostream> #include <cstdlib> using namespace std; int isprime(int num, int i) { if (i == 1) { return 1; } else { if (num % i == 0) return 0; else isprime(num, i-1); // should be returned } } int main(int argc, char** argv) { int input = atoi(argv[1]); cout << input << "\t" << isprime(input, input/2) << "\n"; } 回答1 这样的事情只有在返回值偶然位于调用者期望的寄存器中的情况下才起作用。 仅当编译器将其实现为递归函数时,此方法才有效。 从技术上讲,使用不提供返回值的函数的返回值是不确定的行为。 编辑:在现代体系结构上,函数的返回值(可能的值)在特定的硬件寄存器中传递
  • Ruby:Proc#call与收益率(Ruby: Proc#call vs yield)
    问题 thrice Ruby中以下两种实现在行为上有什么区别? module WithYield def self.thrice 3.times { yield } # yield to the implicit block argument end end module WithProcCall def self.thrice(&block) # & converts implicit block to an explicit, named Proc 3.times { block.call } # invoke Proc#call end end WithYield::thrice { puts "Hello world" } WithProcCall::thrice { puts "Hello world" } 通过“行为差异”,我包括错误处理,性能,工具支持等。 回答1 我认为第一个实际上是另一个的语法糖。 换句话说,没有行为上的差异。 第二种形式允许的是将块“保存”在变量中。 然后可以在其他时间点调用该块-回调。 好的。 这次我去做了一个快速基准测试: require 'benchmark' class A def test 10.times do yield end end end class B def test(&block) 10.times do block
  • 显式模板实例化-什么时候使用?(Explicit template instantiation - when is it used?)
    问题 休息几周后,我尝试通过David Vandevoorde和Nicolai M. Josuttis撰写的“模板–完整指南”一书来扩展和扩展模板的知识,而现在我想了解的是模板的显式实例化。 我实际上没有这种机制的问题,但是我无法想象我想要或想要使用此功能的情况。 如果有人可以向我解释,我将不胜感激。 回答1 直接从https://docs.microsoft.com/zh-cn/cpp/cpp/explicit-instantiation复制: 您可以使用显式实例化来创建模板化类或函数的实例化,而无需在代码中实际使用它。 因为这在创建使用模板进行分发的库(.lib)文件时很有用,所以未实例化的模板定义不会放入对象(.obj)文件中。 (例如,libstdc ++包含std::basic_string<char,char_traits<char>,allocator<char> > (即std::string )的显式实例化,因此每次使用std::string的函数时,该函数都相同不需要将代码复制到对象。编译器只需要将它们引用(链接)到libstdc ++。) 回答2 如果定义模板类,则只想为几个显式类型工作。 像普通类一样,将模板声明放在头文件中。 像普通类一样,将模板定义放在源文件中。 然后,在源文件的末尾,仅显式实例化要使用的版本。 愚蠢的例子: //
  • 是否在函数中显式调用return(Explicitly calling return in a function or not)
    问题 不久前,我被R核心团队的Simon Urbanek斥责(我相信),因为他建议用户在函数末尾显式调用return (尽管他的注释已被删除): foo = function() { return(value) } 相反,他建议: foo = function() { value } 可能在这种情况下是必需的: foo = function() { if(a) { return(a) } else { return(b) } } 他的评论阐明了为什么除非严格需要,否则不要求return是一件好事,但这已被删除。 我的问题是:为什么不是要求return更快,更好,因此最好? 回答1 问题是:为什么不(明确地)调用return更快或更佳,因而更可取? R文档中没有声明做这样的假设。 主页上的“功能”显示: function( arglist ) expr return(value) 不打电话回去会更快吗? function()和return()都是原始函数,即使不包含return()函数, function()本身也会返回上次求值的值。 以最后一个值作为参数调用.Primitive('return') return()作为return()可以完成相同的工作,但还需.Primitive('return')调用一次。 这样(通常)不必要的.Primitive('return'
  • 为什么在具有多个interfaces()的对象中实现QueryInterface()时,我到底为什么需要显式的转换(Why exactly do I need an explicit upcast when implementing QueryInterface() in an object with multiple interfaces())
    问题 假设我有一个实现两个或多个COM接口的类: class CMyClass : public IInterface1, public IInterface2 { }; 我看到的几乎每个文档都建议,当我为IUnknown实现QueryInterface()时,我会明确将该指针向上转换为接口之一: if( iid == __uuidof( IUnknown ) ) { *ppv = static_cast<IInterface1>( this ); //call Addref(), return S_OK } 问题是为什么我不能只复制这个? if( iid == __uuidof( IUnknown ) ) { *ppv = this; //call Addref(), return S_OK } 文档通常说,如果我做后者,我将违反以下要求:在同一对象上对QueryInterface()的任何调用都必须返回完全相同的值。 我不太明白。 难道他们的意思是,如果我QI()用于IInterface2和调用QueryInterface()通过该指针C ++将通过此略有不同,如果我QI()用于IInterface2因为C ++每次都会使这点到子对象? 回答1 问题是, *ppv通常是void* -直接分配this它会简单地把现有的this指针,并给予*ppv它的值
  • 为什么在std :: cout上显式调用operator <<会导致意外输出?(Why does explicitly calling operator<< on std::cout cause unexpected output?)
    问题 我只是好奇如果我在std::cout显式调用operator<<会发生什么,因为我知道a.operator()与a()完全相同。 所以我做到了,它打印出一些奇怪的东西: #include <iostream> using std::cout; int main() { cout.operator<<("Hello World"); } Output: 0x80486a0 奇怪的是,它输出一个地址(该地址可能与您不同,但仍应是一个地址)。 我在想这是字符串的地址,所以我尝试对其进行解引用以使其输出字符串: *( cout.operator<<("Hello World") ); 但是我得到了一个很长的错误 no match for operator* in '*std::cout.std::basic_ostream<... 我认为这很奇怪。 std::cout定义没什么让我相信这会引起任何不同的行为; 还考虑到显式调用操作符函数没有区别(或至少应该如此)的事实。 那我为什么要得到这个输出呢? 为什么显式调用运算符时会收到地址而不是字符串本身? 这甚至是内存中的地址还是仅仅是垃圾输出? 任何答复表示赞赏。 回答1 内置字符串的输出运算符(即以char const*作为参数的on)不是std::ostream的成员。 使用char const*是非成员函数的运算符将称为
  • 为什么.append()时+运算符为什么不更改列表?(Why does not the + operator change a list while .append() does?)
    问题 我正在研究Udacity,Dave Evans介绍了有关列表属性的练习 list1 = [1,2,3,4] list2 = [1,2,3,4] list1=list1+[6] print(list1) list2.append(6) print(list2) list1 = [1,2,3,4] list2 = [1,2,3,4] def proc(mylist): mylist = mylist + [6] def proc2(mylist): mylist.append(6) # Can you explain the results given by the four print statements below? Remove # the hashes # and run the code to check. print (list1) proc(list1) print (list1) print (list2) proc2(list2) print (list2) 输出是 [1, 2, 3, 4, 6] [1, 2, 3, 4, 6] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4, 6] 因此,在函数中向集合添加6不会显示,但在函数中却没有显示呢? 回答1 因此,在函数中向集合添加6不会显示
  • 为什么要明确实现接口?(Why implement interface explicitly?)
    问题 那么,显式实现接口的好用例到底是什么? 仅仅是为了使使用该类的人们不必查看intellisense中的所有那些方法/属性? 回答1 如果您使用相同的方法和不同的实现来实现两个接口,则必须显式实现。 public interface IDoItFast { void Go(); } public interface IDoItSlow { void Go(); } public class JustDoIt : IDoItFast, IDoItSlow { void IDoItFast.Go() { } void IDoItSlow.Go() { } } 回答2 隐藏非首选成员很有用。 例如,如果同时实现IComparable<T>和IComparable ,通常最好隐藏IComparable重载,以免给人以为您可以比较不同类型的对象。 同样,某些接口也不兼容CLS,例如IConvertible ,因此,如果您未明确实现该接口,则需要CLS兼容的语言的最终用户将无法使用您的对象。 (如果BCL实现者没有隐藏原语的IConvertible成员,那将是非常灾难性的事情:) 另一个有趣的注意事项是,通常使用这样的构造意味着显式实现接口的构造只能通过对接口类型进行装箱来调用它们。 您可以通过使用通用约束来解决此问题: void SomeMethod<T>(T obj) where T
  • 为什么需要在Python方法中显式包含“ self”自变量?(Why do you need explicitly have the “self” argument in a Python method?)
    问题 在Python中的类上定义方法时,它看起来像这样: class MyClass(object): def __init__(self, x, y): self.x = x self.y = y 但是在某些其他语言(例如C#)中,您可以使用“ this”关键字来引用该方法所绑定的对象,而无需在方法原型中将其声明为参数。 这是Python中的有意语言设计决定,还是有一些实现细节需要传递“ self”作为参数? 回答1 我喜欢引用Peters的Python Zen。 “显式比隐式好。” 在Java和C ++中,“ this. 可以推导',除非您有无法推论的变量名。 因此,您有时需要它,而有时则不需要。 Python选择使这种事情变得明确,而不是基于规则。 另外,由于没有暗示或假设,因此公开了部分实现。 self.__class__ , self.__dict__和其他“内部”结构以明显的方式可用。 回答2 这是为了使方法和函数之间的差异最小化。 它使您可以轻松地在元类中生成方法,或在运行时将方法添加到预先存在的类中。 例如 >>> class C(object): ... def foo(self): ... print "Hi!" ... >>> >>> def bar(self): ... print "Bork bork bork!" ... >>> >>> c = C()
  • Why does explicit return make a difference in a Proc?
    def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end def bar b = Proc.new { "return from bar from inside proc" } b.call # control leaves bar here return "return from bar" end puts foo # prints "return from foo from inside proc" puts bar # prints "return from bar" I thought the return keyword was optional in Ruby and that you are always returning whether you request it or not. Given that, I find it surprising that foo and bar have different output determined by the fact that foo contains an explicit return in Proc f
  • asm安装
    第1章 ASM安装 - 3 -1.1 简介 - 3 -1.1.1 ASMLib - 3 -1.1.2 什么是 udev - 4 -1.1.3 Why ASMLIB and why not? - 4 -1.2 在 RHEL 6.4 上安装 Oracle 11gR2 + ASM --使用udev - 6 -1.2.1 检查硬件 - 6 -1.2.2 安装软件包检查 - 8 -1.2.3 修改主机名 - 13 -1.2.4 网络配置 - 13 -1.2.5 磁盘准备 - 13 -1.2.5.1 添加磁盘 - 14 -1.2.5.2 对磁盘进行分区 - 20 -1.2.6 配置目录、用户等 - 22 -1.2.6.1 配置用户及用户组 - 22 -1.2.6.2 创建目录并且配置 grid 和 oracle 用户的配置文件 - 23 -1.2.7 使用udev管理磁盘 - 23 -1.2.7.1 配置 udev 绑定的 scsi_id - 23 -1.2.7.2 创建并配置 udev rules 文件 - 25 -1.2.7.3 添加完成后,重启 udev,不同 Linux 发行版本重启方式不一样。 - 26 -1.2.7.4 查看绑定的 asm,如果此时还是看不到 asm disk,请重启操作系统后再查看。 - 26 -1.2.8 系统内核参数修改 - 27 -1.2.8.1 编辑
  • Ruby中的块和收益(Blocks and yields in Ruby)
    问题 我试图理解块和yield以及它们在Ruby中的工作方式。 如何使用yield ? 我看过的许多Rails应用程序都以怪异的方式使用了yield 。 有人可以向我解释或告诉我去哪里了解他们吗? 回答1 是的,起初有点令人困惑。 在Ruby中,方法可以接收代码块以执行任意代码段。 当一个方法需要一个块时,它会通过调用yield函数来调用它。 例如,这非常方便,它可以遍历列表或提供自定义算法。 请看以下示例: 我将定义一个用名称初始化的Person类,并提供一个do_with_name方法,该方法在调用时将name属性传递给接收到的块。 class Person def initialize( name ) @name = name end def do_with_name yield( @name ) end end 这将允许我们调用该方法并传递任意代码块。 例如,要打印名称,我们将执行以下操作: person = Person.new("Oscar") #invoking the method passing a block person.do_with_name do |name| puts "Hey, his name is #{name}" end 将打印: Hey, his name is Oscar 注意,该块接收一个名为name的变量作为参数(注意
  • 标准为什么要区分直接列表初始化和复制列表初始化?(Why does the standard differentiate between direct-list-initialization and copy-list-initialization?)
    问题 我们知道T v(x); 称为直接初始化,而T v = x; 称为复制初始化,这意味着它将根据x构造一个临时T ,该临时T将被复制/移动到v (最有可能被淘汰)。 对于列表初始化,该标准根据上下文区分两种形式。 T v{x}; T v = {x};时称为直接列表初始化T v = {x}; 称为copy-list-initialization : §8.5.4 [dcl.init.list] p1 [...]列表初始化可以在直接初始化或复制初始化上下文中进行; 在直接初始化上下文中的列表初始化称为直接列表初始化,而在复制初始化上下文中的列表初始化称为copy-list-initialization 。 [...] 但是,整个标准中每个都只有两个以上的引用。 对于直接列表初始化,在创建诸如T{x} (第§5.2.3/3 )之类的临时文件时会提到它。 对于复制列表初始化,它用于return语句中的表达式,例如return {x}; ( §6.6.3/2 )。 现在,下面的代码片段呢? #include <initializer_list> struct X{ X(X const&) = delete; // no copy X(X&&) = delete; // no move X(std::initializer_list<int>){} // only list-init
  • Java转换会带来开销吗? 为什么?(Does Java casting introduce overhead? Why?)
    问题 当我们将一种类型的对象转换为另一种类型时,是否会有开销? 还是编译器可以解决所有问题,并且在运行时没有成本? 这是一般的事情,还是有不同的情况? 例如,假设我们有一个Object []数组,其中每个元素可能具有不同的类型。 但是我们始终可以肯定地知道,例如,元素0是Double,元素1是String。 (我知道这是一个错误的设计,但让我们假设我必须这样做。) Java的类型信息是否仍在运行时保留? 还是编译后一切都被遗忘了,如果我们执行(Double)elements [0],我们将仅跟随指针并将这8个字节解释为双精度,无论是什么? 我不清楚在Java中如何完成类型。 如果您对书籍或文章有任何建议,那么也谢谢。 回答1 有2种类型的转换: 隐式转换,当您将类型从类型转换为更宽泛的类型时,它是自动完成的,并且没有开销: String s = "Cast"; Object o = s; // implicit casting 显式转换,当您从较宽的类型转换为较窄的类型时。 对于这种情况,必须显式使用如下所示的强制类型转换: Object o = someObject; String s = (String) o; // explicit casting 在第二种情况下,运行时会产生开销,因为必须检查这两种类型,并且在强制转换不可行的情况下
  • 为什么在显式调用构造函数时不能引用实例方法?(Why can't I refer to an instance method while explicitly invoking a constructor?)
    问题 有谁知道为什么您可以使用this()或super()在构造函数的第一行中引用static方法,而不是非静态方法? 考虑以下工作: public class TestWorking{ private A a = null; public TestWorking(A aParam){ this.a = aParam; } public TestWorking(B bParam) { this(TestWorking.getAFromB(bParam)); } //It works because its marked static. private static A getAFromB(B param){ A a = new A(); a.setName(param.getName()); return a; } } 以及以下非工作示例: public class TestNotWorking{ private A a = null; public TestNotWorking(A aParam){ this.a = aParam; } public TestNotWorking(B bParam) { this(this.getAFromB(bParam)); } //This does not work. WHY??? private A getAFromB(B param)
  • 为什么枚举要求将类型显式转换为int类型?(Why enums require an explicit cast to int type?)
    问题 这样做不会造成数据丢失,那么必须将枚举显式转换为int的原因是什么呢? 如果它是隐式的,会不会更直观,比如说您有一个更高级别的方法,例如: PerformOperation ( OperationType.Silent type ) PerformOperation调用包装的C ++方法,该方法如下所示: _unmanaged_perform_operation ( int operation_type ) 回答1 枚举有两种主要用法和不一致用法: enum Medals { Gold, Silver, Bronze } [Flags] enum FilePermissionFlags { CanRead = 0x01, CanWrite = 0x02, CanDelete = 0x04 } 在第一种情况下,将这些东西视为数字是没有意义的。 它们存储为整数的事实是实现细节。 您不能在逻辑上加,减,乘或除金,银和青铜。 在第二种情况下,将这些东西视为数字也没有意义。 您不能对它们进行加,减,乘或除。 唯一明智的操作是按位操作。 枚举是糟糕的数字,因此您不应意外地将它们视为数字。 回答2 因为枚举不一定是基于int的: enum关键字用于声明枚举,枚举是一种独特的类型,由一组称为枚举器列表的命名常量组成。 每个枚举类型都有一个基础类型,它可以是除char之外的任何整数类型。 因此
  • 为什么要显式删除构造函数而不是将其私有化?(Why explicitly delete the constructor instead of making it private?)
    问题 什么时候/为什么要显式删除我的构造函数? 假设原因是为了防止使用它,为什么不只是将其private呢? class Foo { public: Foo() = delete; }; 回答1 怎么样: //deleted constructor class Foo { public: Foo() = delete; public: static void foo(); }; void Foo::foo() { Foo f; //illegal } 相对 //private constructor class Foo { private: Foo() {} public: static void foo(); }; void Foo::foo() { Foo f; //legal } 它们本质上是不同的东西。 private告诉您只有类的成员才能调用该方法或访问该变量(或当然是朋友)。 在这种情况下,该类(或任何其他成员)的static方法调用一个类的private构造函数是合法的。 这不适用于已删除的构造函数。 在这里取样。 回答2 为什么显式删除构造函数? 另一个原因: 当我想确保使用初始化程序调用类时,我使用delete 。 我认为这是无需运行时检查即可实现的一种非常优雅的方法。 C ++编译器会为您执行此检查。 class Foo { public: Foo() =
  • scala不显式支持依赖类型的原因是什么?(Any reason why scala does not explicitly support dependent types?)
    问题 存在依赖于路径的类型,我认为可以在Scala中表达Epigram或Agda之类语言的几乎所有功能,但是我想知道为什么Scala不像在其他领域一样很好地支持这种语言(例如,DSLs)? 我是否缺少诸如“没有必要”之类的东西? 回答1 除了语法上的便利,单例类型,路径依赖类型和隐式值的组合意味着Scala对依赖类型有着令人惊讶的良好支持,正如我尝试在无形状中演示的那样。 Scala对依赖类型的内在支持是通过路径依赖类型。 这些允许类型依赖于像这样通过对象(即值)图的选择器路径, scala> class Foo { class Bar } defined class Foo scala> val foo1 = new Foo foo1: Foo = Foo@24bc0658 scala> val foo2 = new Foo foo2: Foo = Foo@6f7f757 scala> implicitly[foo1.Bar =:= foo1.Bar] // OK: equal types res0: =:=[foo1.Bar,foo1.Bar] = <function1> scala> implicitly[foo1.Bar =:= foo2.Bar] // Not OK: unequal types <console>:11: error: Cannot prove that
  • 显式关键字是什么意思?(What does the explicit keyword mean?)
    问题 explicit关键字在C ++中是什么意思? 回答1 允许编译器进行一次隐式转换,以将参数解析为函数。 这意味着编译器可以使用可通过单个参数调用的构造函数从一种类型转换为另一种类型,以便获得参数的正确类型。 这是带有可用于隐式转换的构造函数的示例类: class Foo { public: // single parameter constructor, can be used as an implicit conversion Foo (int foo) : m_foo (foo) { } int GetFoo () { return m_foo; } private: int m_foo; }; 这是一个带有Foo对象的简单函数: void DoBar (Foo foo) { int i = foo.GetFoo (); } 这是调用DoBar函数的位置: int main () { DoBar (42); } 该参数不是Foo对象,而是int 。 但是, Foo有一个采用int构造函数,因此可以使用该构造函数将参数转换为正确的类型。 允许编译器对每个参数执行一次此操作。 在explicit关键字前面加上构造函数,可以防止编译器使用该构造函数进行隐式转换。 将其添加到上述类中会在函数调用DoBar (42)创建编译器错误。 现在必须使用DoBar (Foo (42)