返回
编程
分类

函数的覆盖和隐藏等,编译器就知道animal

日期: 2020-03-24 05:33 浏览次数 : 75

关于构造函数和析构函数的一个小问题:
vc++在类中可以自己设置构造函数和析构函数,在主程序中可以调用析构函数。
问题:1、如果在主程序中调用了一个实例的析构函数那么对接下来的程序运行有什么样的影响?
      2、在主程序中调用析构函数有用么?
      3、析构函数是不是与构造函数成对出现?是否可以单独执行,如果仅仅调用了析构函数是不是没有任何用处??

本文转自:

以下是笔者在ubuntu系统下编译运行通过的一些反应c++基础特性的例子,包括类,结构体,构造函数,析构函数,函数的重载,this指针,类的继承,虚函数,函数的覆盖和隐藏等。(由于格式问题代码中的乱码是一些文字描述)

下边是一段可以运行的代码,在main函数中调用了子类的析构函数。
#include <iostream.h>
#include <conio.h>

 

 

class animal
{
public:
    animal()
    {
        cout<<"animal construct"<<endl;
    }
    ~animal()
    {
        cout<<"animal deconstruct"<<endl;
    }
    void sleep()
    {
        cout<<"animal sleep"<<endl;
    }
    void eat()
    {
        cout<<"animal eat"<<endl;
    }
    void breath()
    {
        cout<<"animal breath"<<endl;
    }
};

animal.h

/*#include<iostream>
#include<string.h>
using namespace std;
struct Person
{
char name[20];
int num;

class fish : public animal
{
public:
    fish()
    {
        cout<<"fish construct"<<endl;
    }
    ~fish()
    {
        cout<<"fish deconstruct"<<endl;
    }
    void breath()
    {
        cout<<"fish bubblen";
    }
};
void main()
{
    fish fh;
    fh.~fish();        //调用了一次fh的析构函数;
    fh.breath();
    animal an;
    an.breath();
    getch();
    cout<<"n-------the end of the gatch()--------n";    //仅仅做一个标记。看析构函数在哪里开始运行。
}

//在头文件中包含类的定义及类成员函数的声明

};
int main()
{
int i;
int j;
Person leader_name[3]={"li",0,"jia",0,"wang",0};

程序运行的结果为:
animal construct
fish construct
fish deconstruct          //调用fh的析构函数运行结果;
animal deconstruct        //fh的析构函数调用了,又没有新的构造函数运行,为什么运行fh.breath()还有结果?
fish bubble
animal construct
animal breath

class animal

char leader[20];

-------the end of the gatch()--------
animal deconstruct
fish deconstruct          //fh的析构函数一定调用了,在这里又运行一遍???这是为什么呢?
animal deconstruct
press any key ton continue

{

for(i=0;i<10;i++)
{
cin>>leader;
for(j=0;j<3;j++)
if(strcmp(leader,leader_name[j].name)==0)
leader_name[j].num++;

从运行的结果来看fh的构造函数运行了1次,而fh的析构函数“fish deconstruct”运行了两次。这里就是我的问题三的内容,是不是单独调用析构函数是没有任何作用的??

public:

}
for(i=0;i<3;i++)
{
cout<<leader_name[i].name<<":"<<leader_name[i].num<<endl;

    animal();

}

    ~animal();

}

    void eat();

杩欎釜鏄叧浜庣粨鏋勪綋鏁扮粍鐨勪緥瀛?************************/
/*
#include <iostream>
using namespace std;
class point
{
public: int x;
public: int y;
public: void out()
{
cout<<x<<y<<endl;
}

    void sleep();

};

必威官网亚洲体育 ,    virtual void breathe();

int main()
{
point pt;
pt.x=0;
pt.y=0;
pt.out();
return 0;
}
杩欎釜鏄竴涓畝鍗曠殑鑷畾涔夌被鐨勫簲鐢?*************************/
/*
#include<iostream>
using namespace std;
class point
{
public:
int x;
int y;
point()//杩欎釜鏄釜鏋勯€犲嚱鏁板畠涓昏瀹屾垚鐨勬槸瀵圭被鐨勬垚鍛樿繘琛屽垵濮嬪寲瀹氫箟
{
x=10;
y=12;
}
void out()
{
cout<<x<<y<<endl;
}
};
int main()
{
point pt;
pt.out();
return 0;
}
鏋勯€犲嚱鏁扮殑绠€鍗曞簲鐢?**************************/
/*********************
#include<iostream>
using namespace std;
class point
{
public:
int x;
int y;
point()//鏋勯€犲嚱鏁?{
x=0;
y=0;
}
point(int a,int b)//鏋勯€犲嚱鏁?锛岃繖涓湁鍙傛暟
{
x=a;
y=b;
}
void out()
{
cout<<x<<endl;
cout<<y<<endl;
}
};
int main()
{
point pt(2,2);
point pt1;
pt.out();
pt1.out();//鏍规嵁涓嶅悓鐨勫畾涔夎皟鐢ㄥ搴旂殑鍑芥暟
}
////////////////////鍑芥暟鐨勯噸杞界殑绠€鍗曠粌涔?/
/************************************
#include<iostream>
using namespace std;
class point
{
public:

};

 int x;
 int y;
point()
{
x=0;
y=0;
}
point(int a,int b)
{
x=a;
y=b;
}
void out()
{
cout<<x<<endl;
cout<<y<<endl;
}
void init(int x, int y)//this鎸囬拡锛屼粬鎬绘槸鎸囧悜瀵硅薄鏈韩锛屼唬琛ㄥ璞$殑鍦板潃
{
x=x;
y=y;

 

}

animal.cpp

};
int main()
{
point pt1(5,5);
point pt;
pt.init(10,10);//铏界劧init鍑芥暟鏈変袱涓弬鏁帮紝鍥犱负this鎸囬拡鐨勫師鍥犲湪璋冪敤鍑芥暟鏃舵槸榛樿璋冪敤瀵硅薄鏈韩鐨勫湴鍧€鐨勩€?pt.out();
pt1.out();
return 0;

//在源文件中包含类中成员函数的实现

}

 

//this鎸囬拡鐨勭畝鍗曞簲鐢?*???????????????????????????????/????????????????*/
/*******************************************************
#include<iostream>
using namespace std;
class animal
{
public:
void eat()
{
cout<<"鍚冨悆鍚?<<endl;
}
void sleep()
{
cout<<"鐫¤"<<endl;}
void breath()
{
cout<<"鍛煎惛"<<endl;
}

#include "animal.h"         //因为在编译animal.cpp时,编译器不知道animal到底

};
class fish:public animal//绫荤殑缁ф壙鎬э紝fish绫荤户鎵夸簡animal杩欎釜绫讳腑鐨勫嚱鏁?{};
int main()
{
animal an;
fish fh;
an.eat();
fh.sleep();
fh.eat();
fh.breath();
return 1;
}

                            是什么,所以要包含animal.h,这样,编译器就知道animal

//鍏充簬绫荤殑缁ф壙鎬х殑涓€涓皬渚嬪瓙
**********************************************************/
/*
#include<iostream>
using namespace std;
class animal
{
public:
animal()
{
cout<<"鐖剁被鐨勬瀯閫犲嚱鏁板紑濮?<<endl;
}
~animal()
{
cout<<"鐖剁被鐨勬瀽鏋勫嚱鏁?<<endl;

                            是一种类的类型

}

#include <iostream.h>       //在包含头文件时,<>和""有什么区别?<>和""表示编译器

};
class fish:animal
{
public:
fish()
{
cout<<"瀛愮被鏋勯€犲嚱鏁?<<endl;
}
~fish()
{
cout<<"瀛愮被鐨勬瀽鏋勫嚱鏁?<<endl;
}
};
int main()
{
fish fh;
return 0;
}
//瀛愮被鍦ㄨ皟鐢ㄨ嚜宸辩殑鏋勯€犲嚱鏁版椂娴佺▼搴旇鏄厛璋冪敤鐖剁被鐨勬瀯閫犲嚱鏁扮劧鍚庡瓙绫荤殑鏋勯€犲嚱鏁板瓙绫荤殑鏋愭瀯鍑芥暟鏈€鍚庢槸鐖剁被鐨勬瀽鏋勫嚱鏁般€傚浜庣埗绫荤殑鐨勬瀯閫犲嚱鏁板惈鏈夊弬鏁版儏鍐靛瓙绫荤殑鏋勯€犺鏄剧ず鐨勫幓璋冪敤鐖剁被鐨勬瀯閫犲嚱鏁版墠琛屻€?/////////////////////////////////////////////////////////////绫讳腑鐨勬垚鍛樻湁涓夌绫诲瀷public private protect 鍦ㄧ被鐨勭户鎵垮叧绯讳腑锛屽瓙绫诲鏋滄槸浠ublic缁ф壙鐖剁被锛屽熀绫荤殑鎴愬憳浠嶇劧鏄互鍘熸潵鐨勮闂潈闄愬湪瀛愮被涓璁块棶銆傞粯璁ょ殑鎯呭喌鏄槸浠rivate绫诲舰璁块棶鐨勶紝杩欑鎯呭喌鍩虹被鐨勬垚鍛樺皢浠rivate绫诲瀷鍦ㄥ瓙绫讳腑琚闂紝褰撲互public绫诲瀷璁块棶鏃讹紝鍩虹被鐨刾ublic鍜宲rotect鍙橀噺鍦ㄥ瓙绫讳腑閮藉彉鎴愪簡public绫诲瀷鐨勮闂潈闄愩€?//鐖剁被涓殑private绫诲瀷鍙橀噺涓嶈兘琚瓙绫昏闂€?
///////////////////////
#include<iostream>
using namespace std;
class A
{
public:
void out();
};
class B
{
public:
void out1();
};
void A::out()
{
cout<<"A绫讳腑鐨勫嚱鏁?<<endl;
}
void B::out1()
{
cout<<"B绫荤殑鍑芥暟"<<endl;
}
class C:public A,public B//瀛愮被鍚屾椂缁ф壙涓や釜鐖剁被
{
public:
void show();
};
void C::show()
{
cout<<"瀛愮被涓殑鍑芥暟"<<endl;
}
int main()
{
C c1;
c1.out();
c1.out1();
c1.show();
return 0;
}
//瀛愮被鐨勫閲嶇户鎵夸緥瀛?
#include<iostream>
using namespace std;
class animal
{
public:
void eat()
{cout<<""<<endl;}
 void breath()
{cout<<"鍔ㄧ墿鍛煎惛"<<endl;}
};
class fish:public animal
{
public:
void breath()
{cout<<"fish breath"<<endl;}
};
int main()
{
fish fh;
fh.breath();
}

                            在搜索头文件时的顺序不同,<>表示从系统目录下开始搜索,

///////////////////////////////////////////////
//鍏充簬鍑芥暟鐨勮鐩栵紝闅愯棌锛岄噸杞戒箣闂寸殑鍏崇郴锛氬嚱鏁扮殑瑕嗙洊瑕佹眰鐖剁被鍜屽瓙绫荤殑鍑芥暟瀹屽叏涓€鏍峰寘鎷弬鏁版儏鍐碉紝鍚屾椂鍩虹被鍑芥暟瑕佹槸铏氬嚱鏁帮紝涓や釜鍑芥暟涓€涓湪鍩虹被涓€涓湪瀛愮被銆傚嚱鏁扮殑闅愯棌涔熸槸鍦ㄥ熀绫讳笌瀛愮被涓紝涓嶅悓涔嬪鏄熀绫荤殑鍑芥暟涓嶆槸铏氬嚱鏁帮紝鍩虹被鍜屽瓙绫昏涓€鏍凤紙鍙傛暟鍙互蹇界暐锛夎繖绉嶆儏鍐典笅瀛愮被涓殑鍑芥暟灏嗕細鎶婂熀绫讳腑鐨勫嚱鏁伴殣钘忋€傚嚱鏁扮殑閲嶈浇鏄湪涓€涓被涓彲浠ユ湁澶氫釜鍑芥暟鍚嶄竴鏍风殑鍑芥暟瀛樺湪銆?*/
#include<iostream>
using namespace std;
class A
{
public:
virtual void fn(int i)
{
cout<<"鍩虹被铏氬嚱鏁?<<endl;
}
void yfn(int f)
{
cout<<"鍩虹被鍑芥暟"<<endl;
}

                            然后再搜索PATH环境变量所列出的目录,不搜索当前目录;

};
class B:public A
{
public:
void fn(int i)
{
cout<<"瀛愮被鍑芥暟"<<endl;//瑕嗙洊浜嗗熀绫荤殑铏氬嚱鏁?}

                            ""是表示先从当前目录搜索,然后是系统目录和PATH环境

void yfn(int c)
{
cout<<"瀛愮被鍑芥暟1"<<endl;//闅愯棌浜嗗熀绫荤殑鍑芥暟
}
};
int main()
{
B b;//瀹氫箟涓€涓瓙绫诲彉閲?A *pa=&b;//瀹氫箟涓€涓熀绫荤殑鎸囬拡鎸囧悜瀛愮被鐨勫湴鍧€
B *pb=&b;//瀹氫箟涓€涓瓙绫荤殑鎸囬拡鎸囧悜瀛愮被鐨勫湴鍧€
A a;
A *pA=&a;
pa->fn(5);
pb->A::fn(5);
pA->fn(5);
pa->yfn(2);
pb->yfn(2);
return 0;
}
///////////////////////////鎺屾彙c++,涓昏鏄痗++璇硶鐨勪竴浜涘熀鏈壒寰?

                                 变量所列出的目录。所以如果我们知道头文件在系统目录下

 

                            就可以直接用<>,这样可以加快搜索速度

animal::animal()            //::叫做作用域标识符,用于指明一个函数属于哪个类或一

                            个数据成员属于哪个类。::前面如果不跟类名,表示是全局

{                           函数(即非成员函数)或全局数据

}                          

 

animal::~animal()

{

}

 

void animal::eat()          //注意:虽然我们在函数体中什么也没写,但仍然是实现了

                            这个函数

{

}

 

void animal::sleep()

{

}

 

void animal::breathe()      //注意,在头文件(.h文件)中加了virtual后,在源文

                            件(.cpp文件)中就不必再加virtual了

{                          

 

    cout<<"animal breathe"<<endl;

}

 

fish.h

#include "animal.h"         //因fish类从animal类继承而来,要让编译器知道

                            animal是一种类的类型,就要包含animal.h头文件

class fish:public animal

{

public:

     void breathe();

};

 

fish.cpp

#include "fish.h"

#include <iostream.h>

void fish::breathe()

{

    cout<<"fish bubble"<<endl;

}

 

EX10.cpp

#include "animal.h"

#include "fish.h"

void fn(animal *pAn)

{

    pAn->breathe();

}

void main()

{

    animal *pAn;

    fish fh;

    pAn=&fh;

    fn(pAn);

}

现在我们就可以按下键盘上的F7功能键编译整个工程了,编译结果如下:

 

为什么会出现类重复定义的错误呢?请读者仔细查看EX10.cpp文件,在这个文件中包含了animal.h和fish.h这两个头文件。当编译器编译EX10.cpp文件时,因为在文件中包含了animal.h头文件,编译器展开这个头文件,知道animal这个类定义了,接着展开fish.h头文件,而在fish.h头文件中也包含了animal.h,再次展开animal.h,于是animal这个类就重复定义了。

读者可以测试一下,如果我们多次包含iostream.h这个头文件,也不会出现上面的错误。要解决头文件重复包含的问题,可以使用条件预处理指令。修改后的头文件如下:

animal.h

#ifndef ANIMAL_H_H      //我们一般用#define定义一个宏,是为了在程序中使用,使程

                            序更加简洁,维护更加方便,然而在此处,我们只是为了判断

#define ANIMAL_H_H      ANIMAL_H_H是否定义,以此来避免类重复定义,因此我们没有为

                        其定义某个具体的值。在选择宏名时,要选用一些不常用的名字,

class animal            因为我们的程序经常会跟别人写的程序集成,如果选用一个很常用

                        的名字(例如:X),有可能会造成一些不必要的错误

{

public:

     animal();

     ~animal();

     void eat();

     void sleep();

     virtual void breathe();

};

#endif

 

fish.h

#include "animal.h"

#ifndef FISH_H_H

#define FISH_H_H

class fish:public animal

{

public:

     void breathe();

};

#endif

我们再看EX10.cpp的编译过程。当编译器展开animal.h头文件时,条件预处理指令判断ANIMAL_H_H没有定义,于是就定义它,然后继续执行,定义了animal这个类;接着展开fish.h头文件,而在fish.h头文件中也包含了animal.h,再次展开animal.h,这个时候条件预处理指令发现ANIMAL_H_H已经定义,于是跳转到#endif,执行结束。

通过分析,我们发现在这次的编译过程中,animal这个类只定义了一次。