C++-以下代码能够通过编译运行吗

C++-以下代码能够通过编译运行吗

夜无邪 发布于 2017-06-09 字数 569 浏览 1137 回复 5

看以下一段C++代码:

class Transaction {
public:
Transaction()
{ init(); }

virtual void logTransaction() const = 0;
...

private:
void init()
{
...
logTransaction();
}
};

class BuyTransaction: public Transaction {
public:
virtual void logTransaction() const;

...
};

class SellTransaction: public Transaction {
public:
virtual void logTransaction() const;

...
};

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

想挽留 2017-10-26 5 楼

可以,因为基类Transaction 的logTransaction是纯虚函数,所以基类是抽象类不能被初始化。而继承自基类的派生类是实现类,实现了logTransaction函数。派生类的init中调用的是自己定义的函数,没有什么问题。由于构造函数构造顺序的原因,构造函数中调用虚函数,必定时本类中定义的函数,不会调用到派生类定义的函数。

晚风撩人 2017-09-18 4 楼

其实这个问题, Effective c++中有提到: 第9条:永远 不要在构造或析构的过程中调用虚函数

偏爱自由 2017-08-03 3 楼

一、修改了一下你的代码,如下:

#include<iostream>
using namespace std;

class Transaction
{
public:
Transaction()
{ init(); }

virtual void logTransaction() const
{
cout<<"Transaction"<<endl;
}

private:
void init()
{
logTransaction();
}
};

class BuyTransaction: public Transaction
{
public:
virtual void logTransaction() const
{
cout<<"BuyTransaction"<<endl;
}
};

class SellTransaction: public Transaction
{
public:
virtual void logTransaction() const
{
cout<<"SellTransaction"<<endl;
}
};

int main()
{
BuyTransaction buy;
SellTransaction sell;
Transaction trans;

return 0;
}

运行结果如下:

从结果看显然没有实现你要的功能,那么怎么实现你要的功能呢?可以用到“虚拟构造函数”。

二、 什么是“虚构造函数(virtual constructor)”
一种允许你做一些 C++ 不直接支持的事情的用法。

你可能通过虚函数 virtual clone()(对于拷贝构造函数)或虚函数 virtual create()(对于默认构造函数),得到虚构造函数产生的效果。

看下面的代码:

 class Shape {
public:
virtual ~Shape() { } // 虚析构函数
virtual void draw() = 0; // 纯虚函数
virtual void move() = 0;
// ...
virtual Shape* clone() const = 0; // 使用拷贝构造函数
virtual Shape* create() const = 0; // 使用默认构造函数
};

class Circle : public Shape {
public:
Circle* clone() const { return new Circle(*this); }
Circle* create() const { return new Circle(); }
// ...
};

class Square : public Shape {
public:
Square* clone() const { return new Square(*this);}
Square* create() const { return new Square(); }
// ...
};

因为它能建立新对象,它的行为与构造函数相似,而且因为它能建立不同类型的对象,我们称它为虚拟构造函数。
虚拟构造函数是指能够根据输入给它的数据的不同而建立不同类型的对象。
虚拟构造函数在很多场合下都有用处,从磁盘(或者通过网络连接,或者从磁带机上)读取对象信息只是其中的一个应用。

下面代码展示了如何使用这种“虚拟构造函数”:

 //userCode拟模虚构造函数
void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
// ...
delete s2; // 在此处,你可能需要虚析构函数
delete s3;
}

int main() {

Circle c;
userCode(c);

Square s;
userCode(s);
}

虐人心 2017-07-13 2 楼

这个在构造函数里面调用虚函数,编译器是不会报错的。因为在编译时,编译器检查是否有语法错误,该段代码没有语法错误。在链接时,编译器会做符号相关检查,而该段每个符号都可以找到相关定义,所以链接阶段也不会报错。
但是这段代码的logTransaction()函数却不会实现多态,因为构造的时候都是基类先构造的,派生类并没有构造出来。
如果想实现多态的话。我觉得init写成一个虚函数,作为public接口,每次自己调,比较合适

夜无邪 2017-06-29 1 楼

构造函数里面调用虚函数是有问题的,因为构造函数执行的阶段,派生类还没有构造出来,虚函数指针指向的仍然是基类中的虚函数实现,如果是纯虚函数就是指向空地址,无法调用到派生类的虚函数。从逻辑上来说,基类构造函数执行的阶段还没有派生类,自然没有办法执行派生类的构造。

要么在每个派生类的构造函数中调用相应的代码(把init()移到派生类的构造函数里面),要么把init()作为一个public接口,要求每次创建类之后都手工调用一次。推荐是前一种,不过后一种有的时候也挺有用的。