永发信息网

关于main作为友元函数的问题

答案:4  悬赏:20  手机版
解决时间 2021-12-22 18:06
  • 提问者网友:活着好累
  • 2021-12-22 15:06
#include
#include

using namespace std;
class A
{
private:
static int a;
static int i;
public:
A()
{
++a;
cout<<"Construct the "< }
~A()
{
cout<<"Destructed the "<<(++i)<<" times"< }
friend int main(int argc, char *argv[], A temp);
};
int A::a=0;
int A::i=0;
int main(int argc, char *argv[], A temp)
{
A a;
A b;
A c;
return 0;
}
执行时,只执行了3次构造,却执行了4次析构;也就是说temp没有执行构造函数却执行了析构函数,迷惑中,愿与大家分享难题,也希望知道的同学能告诉我。
最佳答案
  • 五星知识达人网友:酒安江南
  • 2022-01-22 02:31
//先说总结吧
//1 函数应该销毁传进来的值
//2 函数应该销毁自己造的值
//3 函数不能销毁进来的引用
//4 复制值时如果这个值的类型有以自身类型的引用为唯一参数的构造函数,则复制
// 时将采用它进行复制,否则直接复制内存
//5 制造引用不需要构造新的值
//6 参数可以被凭空捏造
//7 参数可以被无情忽略

//其实4中引用的部分和3和5总是同时存在的,所有没说全的其实也包含了这些全部或部分

//根据上的说法,你的temp是由凭空捏造而来的(即没进行构造),但是根据法则1,你的规矩的main是必须要履行销毁的责任的。

//下面是对以上各项说法正证明,花点事件看看吧,至少说明了你的temp哪里来的,以及其他各种情况

//另:射雕英雄先生 - 童生 一级 所说的为代码失误(残疾代码),我所说的捏造指不良代码(包括类似善良的唐僧(操作系统)被扔进女儿国(残疾代码(只有女人是性别残疾转生殖残疾))成为国家安定隐患(程序崩溃)这种情况)通过非正常途径搞活动的行为(没制造temp就对你说temp已经到位了)。

#include
#include

using namespace std;
class A
{
private:
static int a;
static int i;
public:
A()
{
++a;
cout<<"Construct the "< }
~A()
{
cout<<"Destructed the "<<(++i)<<" times"< }
friend int mainDummy(int argc, char *argv[], A temp);
};
int A::a=0;
int A::i=0;
int mainDummy(int argc, char *argv[], A temp)
{
A a;
A b;
A c;
return 0;
}

typedef int (__stdcall *stdmain)(int,char*[]); //stdcall函数的指针,注意参数少了一个
typedef int (__cdecl *cmain)(int,char*[]); //c call函数的指针,注意参数少了一个

stdmain stdm=stdmain(mainDummy);//非正常途径在这里
cmain cm=cmain(mainDummy);//非正常途径在这里

void fun(A& a){}

class B
{
private:
static int a;
static int i;
public :
B()
{
cout<<"make B "<<++a<<" times"< }
B(B& b)
{
cout<<"make B "<<++a<<" times"< }
~B()
{
cout<<"fuck B "<<++i<<" times"< }
};
int B::a=0;
int B::i=0;

void funB0(B b){}
void funB1(B &b){}
void funB2(){}

typedef void (*BF)(B);

BF bf=(BF)funB2;

class C
{
public:
C(){}
private:
C(C& c){} //这个就禁止了直接的复制:C c;C c2=c;这将是非法的
};

int main(int argc, char *argv[],char*env[])
{

//下面这个c call调用不会有问题,因为堆栈有本函数恢复,本函数知道进去时
//堆栈怎么样,也知道出来后该恢复成什么样,而不管被调用者干了什么。
//证明了1 2 4 6
//你的main里的temp就这样被捏造来的,没给你真真的temp。
cm(0,NULL);//通过非正常途径开始搞活动
//上面就发生了构造3次而析构4次

//这个增加块是为了让里面的A在完事后快点销毁。
//这个块总计构造4次析构5次,证明a弄进堆栈个复制过程仅仅是简单的内存拷贝
//而没有执行任何构造!!但是被调用者必须销毁它。因为已经“全交给你了”
//证明了1 2 4
{
A a;
mainDummy(0,NULL,a);
}
//一次构造一个析构,证明对A的赋值是简单的内存拷贝
//证明了4
{
A a;
char buf[sizeof(a)];
A* b=(A*)buf;
*b=a;
}

//这次正好1次构造1次析构,证明函数不会对参数引用的对象进行析构,因为调
//用者没说“都交给你了”,只是给你搭了跟线
//证明了3
{
A a;
fun(a);
}
//一次构造一个析构,证明制造一个对A的引用不需要制造新的A(简直屁话)
//证明了5
{
A a;
A &b=a;
}

//现在看B的表现

//2次构造2次析构,证明把B弄进堆栈使用了构造函数,就是那个B(B&)
//证明了4
{
B b;
funB0(b);
}
//一次构造一个析构,证明制造一个对B的引用不需要制造新的B(又一句屁话)
//证明了3 5
{
B b;
funB1(b);
}
//2次构造1个析构,证明多管闲事没有善果只有恶果,funB2根部不知道你传过来
//了东西并且还要我来销毁。
//证明4 7
{
B b;
bf(b);
}

//下面这个stdcall因为堆栈在被调用者(即mainDummy)里恢复,但是被调用者
//根据自己的参数列表进行恢复时恢复错了,将会导致错误。这里下断点吧
//整整的恶果来了
stdm(0,NULL);//通过非正常途径开始搞活动,但是搞砸了
return 0;
}
全部回答
  • 1楼网友:迟山
  • 2022-01-22 05:47
temp当然也执行构造函数啦。。否则哪来的A对象。。 记住,对象必然是执行构造函数才产生的。 只不过是内部执行,你没有直接调用而已。
  • 2楼网友:神的生死簿
  • 2022-01-22 04:07
函数的形参在编译器生成的是 _main_int_char_A这个样子的。 如果函数中A temp;它会告诉你重定义形参 和编译器机制有关,我的理解
  • 3楼网友:琴狂剑也妄
  • 2022-01-22 03:27
我认为是这样的,C++在调用(当然是非引用调用)以对象作为参数传递的时候,是用复制的方式先复制到临时对象temp中,所以用不着调用该对象的构造函数,而在函数运行完后该函数要销毁这个临时对象变量temp,就得调用析构函数了。 你的main函数也就是这样的在以temp作为临时参数传递的时候,是复制的形式,没调用构造函数,而main运行完销毁temp的时候就析构了它,所以地沟函数要比构造函数多调用一次。这也是我们在调用此类函数时最好采用引用调用的原因。
我要举报
如以上回答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
点此我要举报以上问答信息
大家都在看
推荐资讯