一个例子
首先大家看一个定义的一个虚基类
所谓的虚基类,是指类内包含virtual关键字定义的成员函数
class Abstract_base
{
public:
virtual ~Abstract_base();
virtual void interface() const =0;
virtual const char* mumble() const {return m_mumble;}
protect:
char* m_mumble;
}
上述的虚基类有以下特点:
- 虚的析构函数。(必须的,否则继承的类将没法完全析构,delete BasePointer, BasePointer实际指向的是子类)
- 两个虚的函数
- 一个是接口
- 一个是const char成员
- 一个成员变量
这样的构造成员函数有什问题?
本人的分析
对于虚构造函数,似乎没问题;对于虚拟接口,也没问题,各个子类有自己的实现嘛;对于mumble,子类返回的时候,m_mumble进行了初始化?没有,因为子类没办法初始化 m_mumble, 除非用 Abstract_base::m_mumble这种方式。
class Abstract_base
{
public:
~Abstract_base(){}; // not virtual functions
virtual void interface() const{};
virtual const char* mumble() const {return m_mumble;}
protected:
char* m_mumble;
};
class derived_from_base : public Abstract_base
{
public:
derived_from_base()
{
cout <<"derived ctor" << endl;
}
~derived_from_base()
{
cout << "~ derived dtor" << endl;
}
void interface() const override{}
const char* mumble() const override{ return "asdfsd";}
};
int main()
{
Abstract_base* b = new derived_from_base();
delete b;
return 1;
}
[Running] cd "c:\Users\ssas0e\" && g++ abstract_class.cpp -o abstract_class && "c:\Users\ssas0e\"abstract_class
derived ctor
[Done] exited with code=1 in 3.236 seconds
子类初始化父类的Protect 成员
class Abstract_base
{
public:
~Abstract_base(){};
virtual void interface() const{};
virtual const char* mumble() const {return m_mumble;}
protected:
char* m_mumble;
};
class derived_from_base : public Abstract_base
{
public:
derived_from_base()
{
cout <<"derived ctor" << endl;
char* p = new char[8];
p[0] = '1';
p[1] = '\0';
Abstract_base::m_mumble = p ;
}
~derived_from_base()
{
cout << "~ derived dtor" << endl;
}
void interface() const override{}
const char* mumble() const override{ return Abstract_base::mumble();}
};
int main()
{
// Abstract_base();
derived_from_base b;
cout << b.mumble() << endl;
return 1;
}
运行结果:
derived ctor
1
~ derived dtor
书上的分析
虽然这个class 被设计为一个抽象的base class(其中pure virtual function,使得abstract_base不可能拥有实例,),但它仍然需要一个显示的构造函数,以初始化器成员变量,m_mumble。如果没有这个初始化操作,子类得到的m_mumble是未经过初始化的。
你可能会争辩说,也许Abstract_base
的设计者意图让每一derived class
提供m_mumble
的初始值。然而如果是这样,derived class
的唯一要求就是Abstract_base
必须提供一个带有唯一参数的protect constructor.
Abstract_base::
Abstract_base(char* mumble_value=0):m_mumble(mumble_value)
{}
一般而言,class的data member应该被初始化,并且只能在constructor挥着在class种的其他member funtions中设定初始值。其他的操作会破坏封装性质,使class的维护和修改更加困难。
当然,你也可能争辩说,设计的者的错误并不在于未提供一个explicit constructor,而是它不应该在抽象的base class中声明 成员变量(数据成员,非指针)。这是比较强有利的论点,(把interface与implement分离),但它并不是普世道理。因为将“被共享的数据”取出来放在Base class中,毕竟是一种正当的操作。
读后评论
这里作者认为,虚基类是可以放data member的,因为这个data member是可以共享的数据。但是作者认为,上述的设计,应该提供一个显示的构造函数,不然子类就需要像我最开始的那种 Abstract_base::m_mumble
的方式去给父类的成员变量assign
,破坏编程的封装性