当前位置:C++技术网 > 资讯 > C++抽象类与继承引起的编译问题

C++抽象类与继承引起的编译问题

更新时间:2017-03-01 17:44:46浏览次数:1+次

   昨天,我在写项目时,因为QTableWidget的控件,经常要增加一行与删除一行,刚好有几个QTableWidget的控件,我就把这个增加与删除的方法抽取出来,封装成一个工具类,并设定为抽象类,这样,要用这两个方法的类,只要继承这个抽象类就可以了。

  关于抽象类我用的比较少,基础都忘记了,当时,我索性就在网上查了一下有关C++抽象类的文章,以下是实例代码:

//基类:
class A
{
public:
  A();
  void f1();
  virtual void f2();
  virtual void f3()=0;
  virtual ~A();
};

//子类:
class B : public A
{
public:
  B();
  void f1();
  void f2();
  void f3();
  virtual ~B();
};

//主函数:
int main()
{
  A *m_j=new B();
  m_j->f1();
  m_j->f2();
  m_j->f3();
  delete m_j;
  return 0;
}

咋一看,没有什么问题,但把这段代码复制到VS中一运行,问题出来。


编译器说,构造方法A()与构造方法B()被引用,就是A *m_j=new B()才引用这两个构造方法,而现在基类A与子类B,都只声明了构造方法,没有定义实现,编译器就找不到了,所以,当你把A *m_j=new B()到delete m_j;这几行代码注释掉了,编译就可以通过.


现在,我们再把基类A与子类B的构造方法,都定义实现

class A
{
public:
A(){};
void f1();
virtual void f2();
virtual void f3()=0;
virtual ~A();
};

//子类:
class B : public A
{
public:
B(){};
void f1();
void f2();
void f3();
virtual ~B();
};

这时,它又报f1,f2,f3..几个方法错误,原理是一样,都是因为只声明,没有定义(之前,我还没有注意过此类问题),所以,我们一样要把引用的方法,都定义,才可以编译通过.

错误 1 error LNK2019: 无法解析的外部符号 "public: void __thiscall A::f1(void)" (?f1@A@@QAEXXZ),该符号在函数 _main 中被引用 C:\Documents and Settings\Administrator\My Documents\Visual Studio 2010\Projects\testcpp\testcpp\str1.obj


修改好的代码如下:


class A
{
public:
A(){};
void f1(){};
virtual void f2(){};
virtual void f3()=0;
virtual ~A(){};
};

//子类:
class B : public A
{
public:
B(){};
void f1();
void f2(){};
void f3(){};
~B(){};
};

//主函数:
int main(int argc, char* argv[])
{
A *m_j=new B();
m_j->f1();
m_j->f2();
m_j->f3();
delete m_j;
return 0;
}

以上总结,只有声明,没有定义,链接会失败.编译链接阶段,需要去定义代码,这里的virtual void f3()=0;为纯虚函数也就是抽象方法了,它在基类中定义,继承它的子类一定实现它,不然,子类也是抽象类(不能实例化),  virtual void f2();是虚函数,由于它在基类中,所以也一定有定义体.不然,也会链接错误,这也说明定义函数和链接的关系.我们为什么要定义函数体,为什么出现的是链接错误而不是编译错误.
 我们再来深入讨论一下
编译的过程,这样更利于我们发现问题,总结错误:

 编译的过程是将我们写的语法翻译成汇编语法,进而翻译成二进制的机器码。而编译是分块进行的,以文件为块。一个个的块都翻译好后,就得到了二进制的文件。然后再通过链接,组装起来。而组装的依据就是头文件包含关系和函数声明、调用关系等。
    所以,我们在编译这份代码的时候,f1函数的声明就是一个链接入口。有了这个入口,编译就可以留一个标记,编译时就不需要管f1函数的具体实现,而是留给链接时组装。声明的意义就在于,我提前告知编译器,这个函数是在其他地方定义的,这里可以放心的使用,只要后面一链接就OK。这也就是为什么编译通过,链接却不通过的原因,关于有关C++编译过程,参考一下这个文章,更全面一些

http://www.cnblogs.com/dongdongweiwu/p/4743709.html