不应该在构造函数和析构函数期间调用virtual函数
class Transaction
{
public:
Transaction()
{
init();
}
void init()
{
logTransaction();
}
virtual void logTransaction() = 0;
};
class BuyTransaction: public Transaction
{
void logTransaction(){}
};
int main()
{
BuyTransaction b;
}
在derived class对象的base class构造期间,对象类型是base class而不是derived class
不只是virtual函数会被编译器解析至base class,若使用运行期类型信息,也会把对象视为base class 类型
同样对于析构函数,一旦derived class析构函数开始执行,derived class成员变量便呈现未定义值,C++视他们仿佛不存在,进入base class析构函数后对象便成为一个base class对象
看到了一些关于explicit的介绍,感觉挺好的
class String {
public:
String ( int n )
{
cout << " 我分配了 " << endl;
}; //本意是预先分配n个字节给字符串
String ( const char* p )
{
}; // 用C风格的字符串p作为初始化值
};
int main()
{
String s4 = 10; //编译通过,也是分配10个字节的空字符串
String s5 = 'a'; //编译通过,分配int(‘a’)个字节的空字符串
}
下面的s5赋值容易造成歧义,到底是调用第一个构造函数,还是第二个(其实都是调用第一个)
摘抄了一些别人博客的explicit的介绍:
C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有”显式”那么必然就有”隐式”,那么什么是显示而什么又是隐式的呢?
如果c++类的构造函数有一个参数,那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象,如下面所示:
class MyClass
{
public:
MyClass( int num );
}
//.
MyClass obj = 10; //ok,convert int to MyClass
在上面的代码中编译器自动将整型转换为MyClass类对象,实际上等同于下面的操作:
MyClass temp(10);
MyClass obj = temp;
上面的所有的C++ explicit关键字相关的操作即是所谓的”隐式转换”。
如果要避免这种自动转换的功能,我们该怎么做呢?嘿嘿这就是关键字explicit的作用了,将类的构造函数声明为”显式”,也就是在声明构造函数的时候前面添加上explicit即可,这样就可以防止这种自动的转换操作,如果我们修改上面的MyClass类的构造函数为显式的,那么下面的代码就不能够编译通过了,如下所示:
class MyClass
{
public:
explicit MyClass( int num );
}
//.
MyClass obj = 10; //err,can't non-explict convert
C++ explicit关键字应用方法详解
C++笔记(1)explicit构造函数
曾经在effective c++看到过要用explicit构造函数,但是都忘了,不光忘了规则,连explicit构造函数的作用都忘了,更囧的是,我竟然还写过关于要用explicit关键字的博客
如果搁以前,我一定会埋怨自己,觉得记忆力不行,但是现在的我,并不是以前的我啦,因为我以前只是记住这件事情,并不知道为什么,只是生硬的记忆,现在算是稍微理解为什么了。。。
以后学习也是,没学习一个知识,多花点时间问一下,为什么会是这样,虽然貌似浪费了一点时间,但是可能这个知识就被终身记住了,节约了一大笔时间(不过这不包括考试前突击)
为解决这个问题,也就是需要在base class构造函数中调用virtual函数(其实就是调用derived class的信息),可以通过derived class向base class中传递信息
class Transaction
{
public:
explicit Transaction(string logInfo)
{
logTransaction(logInfo);
}
void logTransaction(string logInfo){}
};
class BuyTransaction: public Transaction
{
public:
BuyTransaction(string para)
: Transaction(createLogString(para))
{
}
private:
static string createLogString(string para){}
};
这里面private static函数 createLogString的运用非常好,保证构造函数调用前就可以使用