构造函数创建隐式对象作为参数 / 使用函数表示法的显式类型转换

看个构造函数创建隐式对象作为参数的例子

#include<iostream>
using namespace std;

class A
{
	int a;
	int b;
public:
	A() { cout << "构造函数" << endl; };
	A(int, int) { cout << "int构造函数" << endl; };
	A(const A &) { cout << "复制构造函数" << endl; };
	void operator()(int a, int b) { cout << "重载()运算符函数" << endl; }
	void sum() { cout << "Sum运算符函数" << endl; }
};

void set(A visit) {
	visit(1, 2);
}

int main()
{
	A a = A();
	set( a );
	cout << endl;

	A *b = new A(1,2);  
	A *c = new A;
	A *d = new A();
	b->sum();
	c->sum();
	d->sum();
        delete b, c, d;

	cout << endl;

	set(A());

	return 0;
}

 set_1( A()); 这个的话就是调用构造函数创建了个临时对象

Yes. The manner in which you are constructing the object in the line:

set(A());
is called functional notation type conversion. This is specified in the section on constructors.

A functional notation type conversion can be used to create new objects of its type. [Note: The syntax looks like an explicit call of the constructor. —end note]

An object created in this way is unnamed.

set(A());
被称为功能符号类型转换。 这在构造函数一节中指定。

功能表示法类型转换可用于创建其类型的新对象。 [注意:语法看起来像构造函数的显式调用。 - 尾注]

以这种方式创建的对象是未命名的。

A constructor is used to initialize objects of its class type. Because constructors do not have names, they are never found during name lookup; however an explicit type conversion using the functional notation will cause a constructor to be called to initialize an object. [ Note: The syntax looks like an explicit call of the constructor. — end note ]

complex zz = complex(1,2.3);
cprint( complex(7.8,1.2) );

构造函数用于初始化其类类型的对象。 因为构造函数没有名称,所以在名称查找期间永远不会找到它们; 但是,使用函数表示法的显式类型转换将导致调用构造函数来初始化对象。 [注意:语法看起来像构造函数的显式调用。]

complex zz = complex(1,2.3);
cprint( complex(7.8,1.2) );
以这种方式创建的对象是未命名的。

使用函数表示法的显式类型转换:

If the initializer is a parenthesized single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression ([expr.cast]). If the type is (possibly cv-qualified) void and the initializer is (), the expression is a prvalue of the specified type that performs no initialization. Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized ([dcl.init]) with the initializer. For an expression of the form T(), T shall not be an array type.

如果初始值设定项是带括号的单个表达式,则类型转换表达式与相应的强制转换表达式([expr.cast])等效(在定义中,如果在意义上定义)。如果类型是(可能是CV限定符)void并且初始化程序是(),则表达式是指定类型的纯右值,它不执行初始化。否则,表达式是指定类型的纯右值,其结果对象使用初始化程序进行直接初始化([dcl.init])。对于T()形式的表达式,T不应是数组类型。

 CV-qualifiers有三种:const-qualifier(const限定符)、volatile-qualifier(volatile限定 符)、以及const-volatile-qualifier(const-volatile限定符)。

glvalue(泛左值) = lvalue (传统意义上的左值)+ xvalue(消亡值,通过右值引用产生)

rvalue (传统意义上的右值) = prvalue(纯右值) + xvalue

来源:https://stackoverflow.com/questions/53422994/does-calling-the-constructor-directly-outside-the-class-implicitly-create-an-obj/53423948#53423948

https://timsong-cpp.github.io/cppwp/n4618/expr.type.conv

感谢P.W老哥的回答。

看一些其它对象作为参数和返回值的例子放松下:

int main()
{
    PriorityQueue pq1();
    pq1.insert(3); // doesn't compile

    PriorityQueue pq2 = PriorityQueue();
    pq2.insert(3); // compiles
}

因为PriorityQueue pq1(); 将被当做是函数体,PriorityQueue返回值类型,pq1是函数名。 

#include <iostream>
using namespace std;
class human
{
  public:
  human(){ human_num++;};
  static int human_num;
  ~human()
  {
     human_num--;
     print();
  }
  void print()
  {
    cout <<"human num is: " <<human_num <<endl;
  }
 
protected:
private:
};
 
int human::human_num = 0;
 
human f1(human x)
{
 x.print();
 return x;
}
 
int main(int argc, char* argv[])
{
  human h1;         //调用human构造函数
  h1.print();       //打印:1
  human h2 = f1(h1);//完成一下动作:
                    //1 调用默认拷贝构造函数,参数传入
                       //2 在f1中打印:1
                    //3 创建临时对象,调用默认拷贝构造函数并初始化h2
                    //4 离开f1,销毁函数内对象,调用析购函数,打印 0
  h2.print();       //打印 0
  return 0;
}                   //销毁h1,h2,调用两次析构函数。

猜你喜欢

转载自blog.csdn.net/weixin_40539125/article/details/84333656