How to make function work with arrays of different pointers?



  • don't know if there is a better way but u can try this.

    template<typename T> 
    void ShowArrayANewStyle(T &Array)
    {
        for(vector<_A *>::size_type n(0); n<Array.size(); ++n)
            cout<<Array[n]->memberA<<" ";
        cout<<endl;
    }
    


  • Thank you.

    I am using "_" to distinguish between types (classes) names and objects names.

    The solution you provided is works. But there is no automatic checking of the inheritance. A user of such function can provide array of every type to the function.

    Is it possible to say compiler that class T in your example MUST be derived from _A class?



  • .filmor schrieb:

    SAn schrieb:

    I hope you can understand english.

    Und ich hoffe du kannst Deutsch.

    Idiot.



  • SAn schrieb:

    I am using "_" to distinguish between types (classes) names and objects names.

    http://www.cse.iitb.ac.in/~karkare/Gc/coding/

    Names starting with _ (underscore) and __ (two underscores) are reserved for compiler writers. These should be avoided.



  • OK. I will try to avoid names starting with "_"

    And I did not write the last message containing "idiot". This is a someone's joke.



  • just pass to the function by pointer/ref to base.

    class A
    {
    };
    
    class B : public A
    {
    };
    
    class C
    {
    };
    
    void func(A const& val)
    { //do something
    }
    
    int main(int, char**)
    {
     A a;
     B b;
     C c;
    
     func(a); //works
     func(b); //should work as well
     func(c); //compile time error
    }
    


  • inp, yes. The problem is to do the same behaviour with arrays of pointers, not just with pointers.



  • how about using functors and foreach/transform ?



  • SAn schrieb:

    inp, yes. The problem is to do the same behaviour with arrays of pointers, not just with pointers.

    yes, i got that.

    but A** isnt B**.
    anyway A** can store elements of type B*
    so why not use a constistent scheme and use just basettype pointerarrays

    class A
    {
    public:
    	virtual void WhoAmI()
    	{	printf("A\n");
    	}
    };
    
    class B: public A
    {
    public:
    	virtual void WhoAmI()
    	{	printf("B\n");
    	}
    };
    
    void func(A** arr, size_t num)
    {
    	for (size_t i = 0; i < num; ++i)
    		arr[i]->WhoAmI();
    }
    
    int main(argc, char**)
    {
    	A** a = new A*[1];
    	A** b = new A*[1];
    
    	a[0] = new A();
    	b[0] = new B();
    
    	func(a, 1);
    	func(b, 1);
    
    	return 0;
    }
    


  • sorry for my sloppy coding though 🙂


  • Mod

    SAn schrieb:

    inp, yes. The problem is to do the same behaviour with arrays of pointers, not just with pointers.

    That is not possible (well, unless you write your own array/vector-class to simulate it - and then there's more than one way to do it too). The reason is simply that when you convert a pointer to a derived class to a pointer to an (accessible and unambigous) base class that converted pointer ceases to point to your derived class. What you can do is converting rvalue pointers, i.e. the values of pointer objects. What you cannot do is to convert lvalues of pointer type to other lvalues of pointer type which pointed to different objects. And that is really what you do when you have an array

    struct Foo {};
    struct Bar : Foo {};
    Bar* x[N];
    

    and try to cast it

    (Foo*(&)[N])x;
    

    Because that means that you want to treat each element of x as if it was an object containing a pointer to Foo. For one, pointers to different types may not have the same object representation. But more importantly, they may not even have the same value when converting one to another (using a suitable point of reference: void*). One pointer points to the Bar object and the other to the Foo subobject within the Bar object and those two need not share the same address. As a general rule - laid down in ancient C times - two different (living - so we ignore unions here) objects do not have the same address. There are only two exceptions to that: the first member of class may have the same address as the class itself (and in case of PODs that is required) and a base class subobject may (but need not) have the same address as the object of the derived class.

    This comes down to a simple rule: never treat arrays polymorphically. Polymorphism applies to individual pointers and references only, never to collections of them.



  • I can not use virtual functions due to performance issues.

    But the previous messages bring me to the following idea:

    inline void CheckType(A *a){;}
    
    template <typename T> void ShowArrayA(vector<T*> &Array)
    {
      if(!Array.size()) return;
    
      CheckType(Array[0]); //Check if T derived from A. I think the clever compiler will generate empty code for this
    
      for(vector<T*>::size_type n(0); n<Array.size(); ++n)
        cout << Array[n]->memberA << ' ';
    
      cout << endl;
    }
    

    This looks ugly, but I think it should work.

    camper, thank you for the detailed explanation.

    But more importantly, they may not even have the same value when converting one to another

    This is new to me. I thought that each pointer points to the very first byte of the object. And base class subobject always have the same address as the object of the derived class.

    But now I understand that it is compiler-specific.



  • SAn schrieb:

    I can not use virtual functions due to performance issues.

    there are plenty ways how to counter performance problems.


  • Mod

    SAn schrieb:

    But more importantly, they may not even have the same value when converting one to another

    This is new to me. I thought that each pointer points to the very first byte of the object. And base class subobject always have the same address as the object of the derived class.

    But now I understand that it is compiler-specific.

    Think multiple inheritance.



  • How about iterators? Seems simpler and more flexible to me.

    template <typename InputIterator>
    void ShowArrayA( InputIterator first, InputIterator last )
    {
      for ( ; first != last; ++first)
        std::cout << (*first)->memberA << ' ';
      std::cout << endl;
    }
    
    #include <algorithm>
    #include <iterator>
    #include <boost/iterator/indirect_iterator.hpp>
    
    std::ostream& operator<<( std::ostream& out, _A const& obj )
    {
      return out << obj.memberA;
    }
    
    template <typename InputIterator>
    void ShowArrayA( InputIterator first, InputIterator last )
    {
      std::copy(
        boost::make_indirect_iterator(first),
        boost::make_indirect_iterator(last),
        std::ostream_iterator<_A>(std::cout, " "));
      std::cout << std::endl;
    }
    
    // test
    
    ShowArrayA(ArrayAOldStyle, ArrayAOldStyle + numObjects);
    ShowArrayA(ArrayANewStyle.begin(), ArrayANewStyle.end());
    ShowArrayA(ArrayBOldStyle, ArrayBOldStyle + numObjects);
    ShowArrayA(ArrayBNewStyle.begin(), ArrayBNewStyle.end());
    

Anmelden zum Antworten