本文在[BigThree设计原则学习]的基础上对于派生类的情形进行讨论。
问题
对于派生类的情形,如果基类实现了BigTree,那么派生类应该怎么实现?需要自己再实现还是用系统默认的?
我自己的理解,派生类要对基类的初始化进行负责,因为派生类是基类的扩展,基类是派生类抽象上的自己,所以后者应对前者的行为负责。但是从层次上来看,二者并不在一个层次。虽然,当我们看派生类的时候,我们看的就是派生类,但是,派生类内部其实蕴含着基类。还是有一个层次关系在的。
所以,对于派生类而言,它是否需要实现BigThree,只需要看它所在的层次是否满足实现BigThree的时机,即是否需要管理动态开辟的内存。如果需要管理,则实现BigThree,反之,不需要。这是它唯一的判别标准。
比如,下面这段代码。
先不从建模的角度考虑我这么设计类是否合理,我只是为了说明派生类实现BigThree的实际。
Base:相当于一个班级信息类,包含学生数量和成绩数组两个成员变量。成绩数组是动态管理的。
Derived:派生于Base,增加了班级名称这个成员变量。
显然,根据上文我的讨论。从层次的角度看,是否需要实现BigThree只需看当前层次是否需要管理动态开辟的内存。Base需要管理(n_, arr_,其中arr_管理动态空间),所以要实现BigThree,Derived不需要管理(只需要管理name_,并不是指针类型),所以不需要实现,利用系统自己生成的即可。下面贴出代码。
代码
- Test.h
#ifndef BASE_DERIVED_H
#define BASE_DERIVED_H
#include <string>
class Base{
public:
Base(){ std::memset( this, 0, sizeof(Base) ); }
Base( int len ) : n_(len) { arr_ = new int[len]; }
public:
~Base(){ dispose(); }
Base( const Base& rhs ){ copy_from( rhs ); }
Base& operator=( const Base& rhs ){
if( this != &rhs ){dispose(); copy_from(rhs);}
return *this;
}
public:
void input_info();
void output_info();
private:
void copy_from( const Base& rhs );
void dispose();
private:
int n_;
int* arr_;
};
class Derived : public Base{
public:
Derived(){}
Derived( int len, std::string name) : Base(len), name_(name) {}
public:
void output_info();
private:
std::string name_;
};
#endif
- Test.cpp
#include <iostream>
#include "Test.h"
void Base::copy_from( const Base& rhs ){
std::memcpy( this, &rhs, sizeof(Base) );
if( rhs.arr_ ){
this->arr_ = new int[this->n_];
for( int i = 0; i < this->n_; ++i ){
this->arr_[i] = rhs.arr_[i];
}
}
}
void Base::dispose(){
if( this->arr_ ){
delete [] this->arr_;
this->arr_ = NULL;
}
}
void Base::input_info(){
std::cout << "请输入" << this->n_ << "名学生成绩:";
for( int i = 0; i < this->n_; ++i ){
std::cin >> this->arr_[i];
}
}
void Base::output_info(){
for( int i = 0; i < this->n_; ++i ){
std::cout << this->arr_[i] << " ";
}
}
void Derived::output_info(){
std::cout << this->name_ << " : ";
Base::output_info();
}
- main.cpp
#include <iostream>
#include "Test.h"
int main( void ){
Derived a;
Derived b(3, "15级1班");
b.input_info();
b.output_info();
std::cout << std::endl;
a = b;
a.output_info();
std::cout << std::endl;
Derived c(b);
c.output_info();
std::cout << std::endl;
return 0;
}
下面则展示,如果派生类需要管理动态开辟内存情形时的代码。由于需要管理动态内存,所以肯定要实现BigThree。那么现在问题来了,既然基类要实现BigThree,派生类也要实现BigThree。那么他们两什么关系。
对于派生类而言,实现BigThree的时候,需要负责基类BigThree的实现。此时,只需要调用基类的相应BigThree函数(注意:不是copy_from和dispose这两个内存管理函数)并且实现当前层次动态开辟内存的管理即可。所以,派生类也要增加copy_from和dispose这两个内存管理函数。但是,他们只负责当前层次的动态开辟内存管理。
注意:我曾错误的只是完全试图使用copy_from和dispose解决问题,把基类内存的管理嵌套在派生类的copy_from和dispose当中解决。
- Test.h
#ifndef BASE_DERIVED_H
#define BASE_DERIVED_H
#include <string>
class Base{
public:
Base(){ std::memset( this, 0, sizeof(Base) ); }
Base( int len ) : n_(len) { grade_ = new int[len]; }
public:
~Base(){ dispose(); }
Base( const Base& rhs ){ copy_from( rhs ); }
Base& operator=( const Base& rhs ){
if( this != &rhs ){dispose(); copy_from(rhs);}
return *this;
}
public:
void input_info();
void output_info();
int get_n() const { return n_; }
private:
void copy_from( const Base& rhs );
void dispose();
private:
int n_;
int* grade_;
};
class Derived : public Base{
public:
Derived(){this->age_ = NULL;}
Derived( int len, std::string name) : Base(len), name_(name) { age_ = new int[len]; }
public:
~Derived(){ dispose(); }
Derived( const Derived& rhs ) : Base(rhs) { copy_from(rhs); }
Derived& operator=( const Derived& rhs ){
if(this != &rhs){ Base::operator=(rhs);dispose(); copy_from(rhs); }
return *this;
}
public:
void input_info();
void output_info();
private:
void copy_from( const Derived& rhs );
void dispose();
private:
std::string name_;
int* age_;
};
#endif
- Test.cpp
#include <iostream>
#include "Test.h"
/* -----------------Base----------------------- */
void Base::copy_from( const Base& rhs ){
std::memcpy( this, &rhs, sizeof(Base) );
if( rhs.grade_ ){// 是否有外部资源
this->grade_ = new int[this->n_];
for( int i = 0; i < this->n_; ++i ){
this->grade_[i] = rhs.grade_[i];
}
}
}
void Base::dispose(){
if( this->grade_ ){
delete [] this->grade_;
this->grade_ = NULL;
}
}
void Base::input_info(){
std::cout << "请输入" << this->n_ << "名学生成绩:";
for( int i = 0; i < this->n_; ++i ){
std::cin >> this->grade_[i];
}
}
void Base::output_info(){
for( int i = 0; i < this->n_; ++i ){
std::cout << this->grade_[i] << " ";
}
}
/* -----------------Derived----------------------- */
void Derived::input_info(){
Base::input_info();
std::cout << "请输入" << this->get_n() << "名学生年龄:";
int n = this->get_n();
for( int i = 0; i < n; ++i ){
std::cin >> this->age_[i];
}
}
void Derived::output_info(){
std::cout << this->name_ << " : ";
Base::output_info();
int n = this->get_n();
for( int i = 0; i < n; ++i ){
std::cout << this->age_[i] << " ";
}
}
void Derived::copy_from( const Derived& rhs ){
this->name_ = rhs.name_;
if( rhs.age_ ){// 是否有外部资源
int n = this->get_n();
this->age_ = new int[n];
for( int i = 0; i < n; ++i ){
this->age_[i] = rhs.age_[i];
}
}
}
void Derived::dispose(){
if( this->age_ ){
delete [] this->age_;
}
}
- main.cpp
#include <iostream>
#include "Test.h"
int main( void ){
Derived a;
Derived b(3, "15级1班");
b.input_info();
b.output_info();
std::cout << std::endl;
a = b;
a.output_info();
std::cout << std::endl;
Derived c(b);
c.output_info();
std::cout << std::endl;
return 0;
}
Introduction Programming with c++ P571给了一个模板。
Child::Child( const Child& object ) : parent(object){
// write the code for copying data fields in child
}
Child& Child::operator=( const Child& object ){
Parent::operator=(object);
// write the code for copying data fields in child
}
Child::~Child(){
// dispose data fields in child
}