Thread: Vectors and custom classes

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    271

    Vectors and custom classes

    I had an inkling the following code wouldn't work before I compiled it but I was vindicated and I don't feel any good.

    Code:
    class A
    {
    private:
    	int i;
    public:
    	A(){}
    	A(A& a){i = a.get_i();}
    	~A(){}
    	void set_i(int j){i = j;}
    	int get_i(){return i;}
    };
    
    int main()
    {
    	A b;
    	vector<A> bb;
    	for(int i = 0; i < 10; i++)
    		bb.push_back(b);
    	bb[0].set_i(3);
    	bb[1].set_i(4);
    	...
    }
    Well, the error message I get is the following:
    c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\vector(810): error C2558: class 'A' : no copy constructor available or copy constructor is declared 'explicit'
    Aren't vectors supposed to work with all sorts of classes and types?

    And how do you make a copy construtor that works with a vector?

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Your copy constructor should use a const parameter. Your get_i method should be const. These things are true in general, and once you fix them, your class should work with vector.

    Actually, you really don't need to define your own copy constructor in that class, since it will be copied correctly by default. The best solution would be to remove your copy constructor and leave a comment that states that default copy is valid.

  3. #3
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Thanks for the feedback, but, huh?

    I tried all possible permutations for the copy constructor:
    Code:
    	A(const A& a){i = a.get_i();}
    Code:
    	const A(A& a){i = a.get_i();}
    Code:
    	A(A& const a){i = a.get_i();}
    None of 'em worked.

    For the get_i:
    Code:
    	const int get_i(){return i;}
    Error message:
    c:\documents and settings\문태선\바탕 화면\ot_ok\main.cpp(51): error C2662: 'A::get_i' : cannot convert 'this' pointer from 'const A' to 'A &'
    So I
    Code:
    	const int get_i(){return (const int) i;}
    But I don't think I've seen anything like that before in any introductory book.

    Anyway, I am in need of some illuminating light.

  4. #4
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Saw this part later.

    Actually, you really don't need to define your own copy constructor in that class, since it will be copied correctly by default. The best solution would be to remove your copy constructor and leave a comment that states that default copy is valid.
    That did get rid of the problem. Unfortunately, I need the copy constructor for the actual code I'm writing.

  5. #5
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    class A
    {
        int i;
    public:
        A(){}
        A(const A& a){i = a.i;}
        ~A(){}
        void set_i(int j){i = j;}
        int get_i(){return i;}
    };
    If you really want to use the get_i function then it needs to be a const member function (not something that returns a const... there is a difference).
    Code:
    class A
    {
        int i;
    public:
        A(){}
        A(const A& a){i = a.get_i();}
        ~A(){}
        void set_i(int j){i = j;}
        int get_i() const {return i;}
    };
    Last edited by hk_mp5kpdw; 05-11-2006 at 01:36 PM.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  6. #6
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Nope, tried it with my actual code and commenting out the copy constructor is not working.

    It's giving me the following error:
    c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xutility(1136): error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const phone' (or there is no acceptable conversion)
    First here's the piece of code in main:
    Code:
    	vector<phone> v3;
    	phone pp;
    
    	for(int i = 0; i < 10; i++)
    		v3.push_back(pp);
    Here's my class definition:
    Code:
    class phone{
    protected:
    	UINT features;
    	UCHAR uc_c_feat;	//core
    	WCHAR wc_s_feat;	//secondary
    	UCHAR uc_t_feat;	//tertiary
    	bool is_null;
    public:
    	phone(){features = 0; uc_c_feat = uc_t_feat = 0; wc_s_feat = 0; is_null = false;}
    	//phone(phone& p)	{features = p.ui_features_value(); uc_c_feat = p.uc_c_feat_value(); wc_s_feat = p.wc_s_feat_value(); uc_t_feat = p.uc_t_feat_value(); is_null = false;}
    	~phone(){}
    	void set_cons(){uc_c_feat ^= CONS; features |= uc_c_feat; is_null = false;}
    	void set_syll(){uc_c_feat ^= SYLL; features |= uc_c_feat; is_null = false;}
    	void set_son(){uc_c_feat ^= SON; features |= uc_c_feat; is_null = false;}
    	void set_lab(){uc_c_feat ^= LAB; features |= uc_c_feat; is_null = false;}
    	void set_cor(){uc_c_feat ^= COR; features |= uc_c_feat; is_null = false;}
    	void set_back(){uc_c_feat ^= BACK; features |= uc_c_feat; is_null = false;}
    	
    	void set_ant(){wc_s_feat ^= ANT; features |= (wc_s_feat << 8); is_null = false;}
    	void set_dist(){wc_s_feat ^= DIST; features |= (wc_s_feat << 8); is_null = false;}
    	void set_high(){wc_s_feat ^= HIGH; features |= (wc_s_feat << 8); is_null = false;}
    	void set_low(){wc_s_feat ^= LOW; features |= (wc_s_feat << 8); is_null = false;}
    	void set_voice(){wc_s_feat ^= VOICE; features |= (wc_s_feat << 8); is_null = false;}
    	void set_constr(){wc_s_feat ^= CONSTR; features |= (wc_s_feat << 8); is_null = false;}
    	void set_cont(){wc_s_feat ^= CONT; features |= (wc_s_feat << 8); is_null = false;}
    	void set_del_rel(){wc_s_feat ^= DEL_REL; features |= (wc_s_feat << 8); is_null = false;}
    	void set_lat(){wc_s_feat ^= LAT; features |= (wc_s_feat << 8); is_null = false;}
    	void set_nas(){wc_s_feat ^= NAS; features |= (wc_s_feat << 8); is_null = false;}
    	
    	void set_spread(){uc_t_feat ^= SPREAD; features |= (uc_t_feat << 24); is_null = false;}
    	void set_atr(){uc_t_feat ^= ATR; features |= (uc_t_feat << 24); is_null = false;}
    	
    	void set_null(){is_null = true;}
    	//core_features* p_c_feat(){return &c_feat;}
    	//secondary_features* p_s_feat(){return &s_feat;}
    	UINT ui_features_value(){return features;}
    	UCHAR uc_c_feat_value(){return uc_c_feat;}
    	WCHAR wc_s_feat_value(){return wc_s_feat;}
    	UCHAR uc_t_feat_value(){return uc_t_feat;}
    	bool b_is_null(){return is_null;}
    	virtual void initialize(){features = 0; uc_c_feat = uc_t_feat = 0; wc_s_feat = 0; is_null = false;}
    	phone* operator=(phone& p){features = p.ui_features_value(); uc_c_feat = p.uc_c_feat_value(); wc_s_feat = p.wc_s_feat_value(); uc_t_feat = p.uc_t_feat_value(); return this;}
    	friend int operator-(phone&, phone&);
    };
    And just in case you need to see it, I've attached my entire project. It's actually a zip file so you'll have to rename the extension to zip.

    Again, any help would be appreciated.
    Last edited by cunnus88; 02-04-2008 at 01:12 AM.

  7. #7
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Lesson learned for "class A" and thanks for teaching me that.

    Now if only I can get my "class phone" to work. And why it won't is friggin beyond me.
    Code:
    class phone{
            ...
    public:
    	phone(){features = 0; uc_c_feat = uc_t_feat = 0; wc_s_feat = 0; is_null = false;}
    	phone(const phone& p)	{features = p.features; uc_c_feat = p.uc_c_feat; wc_s_feat = p.wc_s_feat; uc_t_feat = p.uc_t_feat; is_null = false;}
            ....

  8. #8
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Nevermind, got it.

    From
    Code:
    	phone* operator=(phone& p){features = p.ui_features_value(); uc_c_feat = p.uc_c_feat_value(); wc_s_feat = p.wc_s_feat_value(); uc_t_feat = p.uc_t_feat_value(); return this;}
    to
    Code:
    	phone* operator=(const phone& p){features = p.features; uc_c_feat = p.uc_c_feat; wc_s_feat = p.wc_s_feat; uc_t_feat = p.uc_t_feat; return this;}
    So the way I understand it, if you pass an argument as "const addressof_sometype" you're allowed to access its private member variables directly. Is that right?
    Since it's constant, there's no danger of someone changing the private variables. Right?

    Anyway, c++ is cool. Thanks guys.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> So the way I understand it, if you pass an argument as "const addressof_sometype" you're allowed to access its private member variables directly. Is that right?
    Since it's constant, there's no danger of someone changing the private variables. Right?

    The const just means that you promise not to change the data inside the object. It has nothing to do with the private variables (that was just a separate point being made). You can read those variables as much as you want. If you try to modify them directly, there will be a compiler error. If you call a function (like get_i) that is not marked as const, then the compiler thinks that maybe that function will modify the data inside the object, and it will give an error.

    Making your code const-correct is not the easiest thing, but standard library code like vector expects it to be done, so you should try to always do it from the start with all your code. That means any function parameter that will not be changed should be made const (including reference parameters). That also means that any member functions that don't change the state of the object should be const (like get_i). You can start by going through your current class and identifying those const member functions, and also updating existing functions to take const parameters (like your operator-).

    BTW, why is the operator= returning a Phone*? Normally it would return void, const Phone&, or Phone&.
    Last edited by Daved; 05-11-2006 at 02:02 PM.

  10. #10
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Noted. Didn't make sense to me either when I did it. It just compiled so I let it go.

    Thanks for the pointer.

    Completely unrelated.

    I'm listening to the New Pornographers right now. Twin Cinema to be exact. Go out and buy that album; immediately; no buts; NOW. It is, dare I say it, awesome.

  11. #11
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    One other point... having protected member's seems to indicate you are going to doing some inheritance down the road. You should make the destructor virtual:
    Code:
    class phone
    {
    protected:
        ...
    public:
        ...
        virtual ~phone() {}
        ...
    };
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  12. #12
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Curiouser and Curiouser.

    I thought you couldn't declare constructors and destructors as virtual, but I shall revise that section in my brain.

    Danke.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Only constructors cannot be virtual. It wouldn't make sense if they could, since virtual is used to direct a function call to the proper derived class when you don't know which derived type a pointer or reference refers to. When you call the constructor, you are creating the object, so you always know the derived type.

    And destructors should almost always be virtual if the class is intended to be used as a base class.

  14. #14
    semi-colon generator ChaosEngine's Avatar
    Join Date
    Sep 2005
    Location
    Chch, NZ
    Posts
    597
    In C++ a common guideline is the "Rule of 3".
    if a class requires a custom copy constructor, overloaded = operator or destructor, it generally needs all three.
    "I saw a sign that said 'Drink Canada Dry', so I started"
    -- Brendan Behan

    Free Compiler: Visual C++ 2005 Express
    If you program in C++, you need Boost. You should also know how to use the Standard Library (STL). Want to make games? After reading this, I don't like WxWidgets anymore. Want to add some scripting to your App?

  15. #15
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Thanks for all the helpful advice, folks. With all the attention I've gotten, I feel like a pregnant woman in the maternity ward.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Using C++ Standard library to generate custom Vectors?
    By Zeeshan in forum C++ Programming
    Replies: 8
    Last Post: 04-04-2008, 09:34 AM
  2. Help With Custom Dynamic Arrays
    By feso4 in forum C++ Programming
    Replies: 3
    Last Post: 06-29-2006, 01:05 PM
  3. Stl sets and custom classes.
    By cunnus88 in forum C++ Programming
    Replies: 3
    Last Post: 05-12-2006, 11:58 PM
  4. How To use vectors for custom classes
    By johnnyd in forum C++ Programming
    Replies: 14
    Last Post: 03-25-2003, 10:04 PM