CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 40

Threaded View

  1. #25
    Join Date
    Feb 2005
    Location
    "The Capital"
    Posts
    5,306

    Re: How to avoid dynamic_cast/static_cast

    Visitor solution is okay but it does not look better than having members isDir() and isFile() in that these functions would be making 1 virtual call while the visitor solution makes 2. Good that it hides the keywords "*_cast" but I don't think it is well suited here.

    For composite pattern, I looked at it the first time and tried pulling out some code that can help achieve the search functionality but it too required knowledge if a FSObject is a folder or not. Here is what I roughly got (incomplete but then I don't feel like completing it):
    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    
    class IFSObject
    {
    	public:
    		virtual const std::vector<IFSObject*>& GetChildren() const = 0;
    		virtual const std::string& GetName() const = 0
    		virtual IFSObject& Clone() = 0;
    		//other interfaces
    		virtual ~IFSObject(){}
    };
    
    class File : public IFSObject
    {
    	public:
    		File(const std::string& name_) : name(name_){}
    		const std::vector<IFSObject*>& GetChildren() const{
    			return std::vector<IFSObject*>();
    		}
    		const std::string& GetName() const{
    			return name;
    		}
    		IFSObject& Clone(){
    			return *(new File(name));
    		}
    	private:
    		std::string name;
    }
    
    class Folder : public IFSObject
    {
    	public:
    		Folder(const std::string& name_) : name(name_){}
    		const std::vector<IFSObject*>& GetChildren() const{
    			return children;
    		}
    		void Add(const IFSObject& something){
    			/*Should keep IFSObject ownership*/
    			children.push_back(&(something.Clone()));
    		}
    		void Remove(const IFSObject& something){
    			/*Add remove logic*/
    		}
    		IFSObject& Clone(){
    			return *(new Folder(name));
    		}
    		~Folder(){
    			/*Add children cleanup logic*/
    		}
    	private:
    		std::string name;
    		std::vector<IFSObject*> children; /*may use shared_ptr<T>*/
    }
    
    class Link : public IFSObject
    {
    	/*add implementations with extensions*/
    }
    
    IFSObject* search(const std::string& name, const Folder& folder)
    {
    	//would need to know the actual type
    	//Why??
    	//Because there can be empty folders and links which will not be files.
    }
    
    int main()
    {
    	//create a filesystem
    	Folder folder;
    	//fill folder with various components
    	IFSObject* fsobject_ptr = search("somefile", folder);
    	return 0;
    }
    Or else, I might not have understood composite pattern well. But the thing is the moment a differentiation is necessary (which I think is), the composite pattern becomes a wrong choice.

    Having a variant type might not help as well. Type information seems necessary. A virtual call is necessary.

    There is one advantage with composite pattern though - the virtual call to know the type would be only necessary in the worst cases, i.e. when a directory does not have files and the cases when the FSObject may be a link. For the rest of the iteration one can go without knowing what FSObject* actually points to. That is a choice you can make.

    I also had a quick look at boost::filesystem library where I though they might be having some different solution when finding files in a filesystem. But, alas, they don't have any such mechanism either. They also need to know the "type" information. They use a function named "is_directory". Take a look at the following code:
    Code:
    bool find_file( const path & dir_path,     // in this directory,
                    const std::string & file_name, // search for this name,
                    path & path_found )        // placing path here if found
    {
    	if ( !exists( dir_path ) ) 
    		return false;
    	directory_iterator end_itr; // default construction yields past-the-end
    	for ( directory_iterator itr( dir_path ); itr != end_itr; ++itr )
      	{
        		if ( is_directory( *itr ) )
        		{
          			if ( find_file( *itr, file_name, path_found ) ) return true;
        		}
        		else if ( itr->leaf() == file_name ) // see below
        		{
          			path_found = *itr;
    		      	return true;
        		}
      	}
      	return false;
    }
    So as to conclude my thoughts on this now, there are 2 options: go ahead with what you have already (something as in OP) or use composite pattern with type checking in worst cases. That can be reduced even further with one thing that I am not very sure of - but atleast in *nix and windows doing ls -altr or dir, I always see 2 entries (directories . and ..) may be paths to previous directory and current working directory. This may be a case worth considering whatever you are modelling (I think that is not actually a FS).

    Hope it helps a little bit.
    Last edited by exterminator; December 15th, 2006 at 01:45 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured