C++中关于类重复定义的分析和解决方法

在C++中将类以及类中的成员函数的声明放在.h的头文件中,而将类中成员函数的定义(即实现代码)放在.cpp的源文件中,这样我们的程序设计起来更加的模块化,但是,这样的设计也会带来一些问题,我们分析以下的代码,从中找的问题,并给出问题的解决方法。首先我们在VC下新建一个工程(工程名自己随便命名),然后在此工程下新建两个.h的头文件(文件名分别为Animal.h和 Fish.h),继续新建三个.cpp的源文件(文件名分别是Animal.cpp、Fish.cpp、Main.cpp),完成后分别将以下的代码copy到相应的文件下。

如下图所示:


Animal.h

class Animal
{
public :
           Animal(int height, int weight) ;
           void eat() ;
           void sleep() ;
           virtual void breathe() ;
} ;

Fish.h

#include"Animal.h"
 
class Fish :public Animal
{
public :
      Fish() ;
      void breathe() ;
} ;

Animal.cpp

#include<iostream.h>
#include"Animal.h"
 
Animal::Animal(intheight, int weight)
{
 
}
 
voidAnimal::eat()
{
      cout << "Animal eat"<< endl ;
}
voidAnimal::sleep()
{
      cout << "Animal sleep"<< endl ;
}
void Animal::breathe()
{
      cout << "Animal breathe"<< endl ;
}

Fish.cpp

#include<iostream.h>
#include"Fish.h"
Fish::Fish() :Animal(300, 400)
{}
voidFish::breathe()
{
      cout << "fish breathe"<< endl ;
}

Main.cpp

#include<iostream.h>
#include"Animal.h"
#include"Fish.h"
 
void fun(Animal*pAn)
{
      pAn->breathe() ;
}
 
void main()
{
      Fish fh ;
      Animal *pAn ;
      pAn = &fh ;
      fun(pAn) ;
}

完成后,点击编译后,会发现VC编译器报错,具体如下:


大概意思就是Animal类重复定义。

我们来分析一下源代码。

首先是执行Main.cpp源文件中的代码,发现#include "Animal.h"此句代码,编译器回去查找Animal.h头文件,发现Animal这个类已经定义,继续执行,执行到#include "Fish.h"这句代码时,编译器便会去查找Fish.h头文件,在Fish.h头文件中,编译器执行到#include "Animal.h"时,便又去查找Animal.h头文件中的代码,再次发现类Animal的定义,这样,编译器感觉类Animal重复定义了两次,于是,编译器便会报错。

那么,我们该怎样去解决这种问题呢?

方法一:

既然我们已经分析了出现这种问题的原因,那么,我们可以发现在Main.cpp文件中,我们引用了#include "Animal.h"头文件,而当我们再次去引用#include "Fish.h"头文件时,发现在Fish.h文件中也引用了#include "Animal.h"头文件,既然这样,我们何不在Main.cpp文件中将#include "Animal.h"注释掉,这样就避免了重复定义的问题了,其实这样做也是可以的,但是,我们想想,如果我们在写一个大型的程序时,往往有几十个甚至成百上千个的类,其中的继承关系又是那么的复杂的时候,我们便会很难分析到那块可以不写(注释掉),所以,这种方法不适合大型程序的设计。于是,我们又想出了下面的方法:


方法二:

看如下的代码(保持.cpp文件不变,我们在.h头文件上解决该问题)

Animal.h

#ifndefANIMAL_H_H
#defineANIMAL_H_H
class Animal
{
public :
           Animal(int height, int weight) ;
           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 :
      Fish() ;
      void breathe() ;
} ;
#endif

观察改写后的代码,发现我们在类的定义前后分别加上了#ifndef…#define…#endif语句,哪么这条语句有什么作用呢?还是刚才的分析过程,当编译器去执行Main.cpp源文件中的代码,发现#include "Animal.h"此句代码,编译器回去查找Animal.h头文件,执行到#ifndef ANIMAL_H_H时,编译器会做出如下的判断,若FISH_H_H没有被定义,便定义它(#define FISH_H_H被执行)继续执行,执行到#include "Fish.h"这句代码时,编译器便会去查找Fish.h头文件,在Fish.h头文件中,编译器执行到#include "Animal.h"时,便又去查找Animal.h头文件中的代码,与上面的一样,编译器会判断FISH_H_H定义了没有,若没有,便进行定义,反之,将跳过#ifndef…#endif间的代码,继续向后执行,知道程序执行完毕。

现在再次编译一下更改后的代码,发现程序并没有报错,执行后输出如下:



上面的使用#ifdef…#endif解决重复定义的问题在MFC编程中会经常的看到,所以,希望学习MFC编程的编程爱好者能够好好的阅读和分析一下,亲自做做实验,有利于个人理解。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值