1:为什么不要在构造函数与析构函数中调用虚函数?
先说结论,不要在类的构造或者析构过程中调用虚函数,因为这样的调用永远不会沿类继承树往下传递到子类中去。因为继承中构造的顺序是先构造父类再构造子类。如果在父类的构造函数中调用本应由子类实现的虚函数则会会呈现出现父类的行为。我的理解是这样就违反了多态的原则,所以应当予以抛弃。例如下面的代码:
class Transaction {// 所有交易的基类
public:
Transaction();
virtual void logTransaction() const//建立依赖于具体交易类型的登录项
{
cout<<"在基类中调用log"<<endl;
}
};
Transaction::Transaction() //实现基类的构造函数
{
logTransaction(); //最后,登录该交易
}
class BuyTransaction: public Transaction {
// 派生类
public:
virtual void logTransaction() const //怎样实现这种类型交易的登录?
{
cout<<"在buy中调用log"<<endl;
}
};
class SellTransaction: public Transaction {
//派生类
public:
virtual void logTransaction() const //怎样实现这种类型交易的登录?
{
cout<<"在sell中调用log"<<endl;
}
};
int main()
{
BuyTransaction b1;
}
执行该代码会显示出在基类中调用log。而我们的本意是在调用SellTransaction 或者BuyTransaction的时候实现登录日志,但是现在在构造基类的时候就把他实现了,这样是不对的。所以我们应该怎样做呢?一种办法就是在Transaction中把函 logTransaction改变为一个非虚函数,然后要求派生子类的构造器要把必要的登录信息传递给Transaction的构造器。例如改成下面这样:
class Transaction {
public:
explicit Transaction(const std::string& logInfo);
void logTransaction(const std::string& logInfo) const;//现在是一个非虚函数
...
};
Transaction::Transaction(const std::string& logInfo)
{
...
logTransaction(logInfo);// 现在调用的是一个非虚函数
}
class BuyTransaction: public Transaction {
public:
BuyTransaction( parameters ):Transaction(createLogString(parameters)) { ... } //把登录信息传送给基类的构造函数
...
private:
static std::string createLogString( parameters );
};
2:为什么不重新定义继承而来的缺省参数值,因为virtual函数是动态绑定,而缺省参数值却是静态绑定。所以你可能调用了一个派生类的virtual函数,但是使用到的缺省参数,却是基类的。例如下面的代码:
class Shape
{
public:
virtual void draw(int color=1) const
{
cout<<color<<endl;
}
};
class Rectangle: public Shape
{
public:
virtual void draw(int color=2) const{
cout<<color<<endl;
}
};
class Circle:public Shape
{
public:
virtual void draw(int color) const{
cout<<color<<endl;
}
};
int main()
{
Rectangle r;
Circle c;
Shape *pr = &r;
Shape *pc = &c;
pr->draw();
pc->draw();
}
由于在Circle类中位显示定义缺省值,所以他会调用基类的缺省值,引起未定义的行为。
3:纯虚函数,虚函数和一般函数的选择
1:声明一个pure virtual函数的目的是为了让derived classes只继承函数接口
2:声明(非纯)impure virtual函数的目的,是让derived classes继承该函数的接口和缺省实现
3:声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现
4:公有继承私有继承和保护继承
public protected private
共有继承 public protected 不可见
私有继承 private private 不可见
保护继承 protected protected 不可见
5:如何定义一个只能在堆栈上生成的对象
C++类的对象建立的方式分为两种,静态建立和动态建立,静态建立是建立在栈上,动态建立建立在堆上。静态建立的方式是
A a(),动态建立的方式是A* a=new A()。所以如果要只建立在栈上则将new 运算符设置为私有即可。
private :
void * operator new ( size_t t){} // 注意函数的第一个参数和返回值都是固定的
void operator delete ( void * ptr){} // 重载了new就需要重载delete
如果要只能建立在堆上可以将析构函数设置位私有 ,然后再类中提供destroy 方法来销毁对象。
class A
{
public :
A(){}
void destory(){ delete this ;}
private :
~A(){}
};
6:内联函数、构造函数、静态成员函数可以是虚函数吗?
都不可以。内联函数需要在编译阶段展开,而虚函数是运行时动态绑定的,编译时无法展开; 构造函数在进行调用时还不存在父类和子类的概念,父类只会调用父类的构造函数,子类调用子类 的,因此不存在动态绑定的概念;静态成员函数是以类为单位的函数,与具体对象无关,虚函数是 与对象动态绑定的,因此是两个不冲突的概念。