在执行期间将父类转换为子类

时间:2019-07-02 08:01:05

标签: c++ inheritance casting

我有一个名为SavableFile的父类,还有两个SaveA继承的类SaveBSavableFile

它们的定义如下:

class SavableFile {
    SavableFile(std::string _filename) : p_filename(_filename){}
    virtual void write() = 0;
protected:
    std::string p_filename;
}

class SaveA : public SavableFile {
   SaveA(std::string _filename) : SavableFile(_filename) {}
   void write() {
        std::cout << "A" << std::endl; 
   }
}

class SaveB : public SavableFile {
   SaveB(std::string _filename) : SavableFile(_filename) {}
   void write() {
        std::cout << "B" << std::endl; 
   }
}

我的问题是:是否可以创建一个SavableFile并使用文件名的扩展名将此savableFile转换为saveA或saveB?像

 SavableFile(std::string _filename) : p_filename(_filename){
     std::string ext = GetExtension(_filename);   
     //this is purely fictionnal, it's only in order to give an idea, i'm not sure if there is a way to do that, that's why i'm asking
     if (ext.lower() == "a"){
          *this = dynamic_cast<SaveA>(*this);
     } 
     else {
          *this = dynamic_cast<SaveB>(*this);
     }
}

这样我就可以做这样的事情:

int main(int argc, char* argv[]){
    SavableFile svA("foo.a");
    //Here, SavableFile has been changed into SaveA class because of the constructor of SavableFile
    svA->write();
    //Here should be writed "A"
    SavableFile svB("bar.b");
    svB->write();
    //Here should be writed "B"
}

我总是可以在主体中进行测试,以检查是否必须创建SaveA或SaveB类,但是我认为这不是解决问题的好方法。但是我找不到做到这一点的方法,也没有找到好的措辞来在某处寻求帮助... 可能吗? 非常感谢!

2 个答案:

答案 0 :(得分:1)

否,您不能将现有对象转换为其他类型。

另一种方法是named constructor pattern

print = () => {
    let { state } = this.state;
    qz.websocket.connect()
    .then(function() {
     return qz.printers.find("BillPrinter");
   }).then(function(printer) {
         var config = qz.configs.create(printer);
         var data = [
              `${state.restaurant_name}` + '\x0A',
              `${state.restaurant_address}`
         ]

         return qz.print(config, data);
    });
}

这样做的缺点是总是返回动态分配的指针。为了解决这个问题,您可以添加另一层抽象:class SavableFile { public: static SavableFile *create(std::string _filename); // named constructor virtual void write() = 0; protected: SavableFile(std::string _filename) : p_filename(_filename){} // actual constructor now protected std::string p_filename; }; SavableFile *SavableFile::create(std::string _filename) { std::string ext = GetExtension(_filename); if (ext.lower() == "a"){ return new SaveA(_filename); } else { return new SaveB(_filename); } } 将包含一个SavableFile,其中private FileSaver *p_filesaver是仅包含FileSaver函数的接口。

答案 1 :(得分:1)

您可以使用 Factory方法设计模式来做到这一点:

class Factory {
public:
    static SavableFile* get(std::string _filename) {
        std::string ext = GetExtension(_filename);
        if (ext.lower() == "a") {
            return new SaveA(_filename);
        } 
        else {
          return new SaveB(_filename);
        }
        return nullptr;
    }
};

完整代码:

class SavableFile {
public:
    SavableFile(std::string _filename) : p_filename(_filename) {}
    virtual void write() = 0;
protected:
    std::string p_filename;
};

class SaveA : public SavableFile {
public:
    SaveA(std::string _filename) : SavableFile(_filename) {}
    void write() override {
        std::cout << "A" << std::endl; 
    }
};

class SaveB : public SavableFile {
public:
   SaveB(std::string _filename) : SavableFile(_filename) {}
   void write() override {
        std::cout << "B" << std::endl; 
   }
};

class Factory {
public:
    static SavableFile* get(std::string _filename) {
        std::string ext = GetExtension(_filename);
        if (ext.lower() == "a") {
            return new SaveA(_filename);
        } 
        else {
            return new SaveB(_filename);
        }
        return nullptr;
    }
};

int main(int argc, char* argv[]) {
    SavableFile* svA = Factory::get("foo.a");
    // It is better to check here if the pointer is not null.
    svA->write();
    SavableFile* svB = Factory::get("bar.b");
    // It is better to check here if the pointer is not null.
    svB->write();

    delete svA;
    delete svB;
    return 0;
}