Thread: Base and Derived Class Constructors with Different Signatures

  1. #1
    Registered User
    Join Date
    Mar 2016
    Posts
    203

    Base and Derived Class Constructors with Different Signatures

    Base class constructor:
    Code:
    Port(const char* brand = "none", const char* style = "none", int bottles = 0)
    Derived class constructor:
    Code:
    VintagePort(const char* brand = "none", int bottles = 0, const char* nickname = "none", int year = 0)
    Vintage is a style of port and hence style has been removed from the derived class, VintagePort, constructor.

    I have written the derived class constructor as follows:
    Code:
    VintagePort::VintagePort(const char* brand, int bottles, const char* nickname, int year){
    	Port::SetBrand(brand);
    	Port::SetBottles(bottles);
    	m_nickname = new char[strlen(nickname)+1];
    	strcpy(m_nickname, nickname);
    	m_year = year;
    }
    But I am not sure how to write the derived class copy constructor. Here is my unsuccessful attempt and any advice would be most welcome:
    Code:
    VintagePort::VintagePort(const VintagePort& vp){
    	this->GetBrand()	=	new char [strlen(vp.Port::GetBrand())+1)]
    }
    FYI, the problem asks to use arrays to practice dynamic memory allocation.
    PS:
    The function names are self-explanatory; nevertheless for the sake of completeness, here is the full code so far:

    Code:
    #include<iostream>
    #include<cstring>
    using namespace std;
    class Port{
    	private:
    		char* m_brand;
    		char m_style[20];
    		int m_bottles;
    	public:
    		Port(const char* brand = "none", const char* style = "none", int bottles = 0);
    		Port(const Port& p); // copy constructor; 
    		virtual ~Port(){delete[]m_brand;}
    		Port& operator=(const Port& p);
    		Port& operator+=(int b);// adds b to bottles; 
    		Port& operator-=(int b);//subtracts b from bottles if available; 
    		int BottleCount() const { return m_bottles;};
    		void SetBrand(const char* brand = "none");
    		char* GetBrand(){return m_brand;};
    		void SetBottles(int bottles){m_bottles = bottles;};
    		int GetBottles(){return m_bottles;};
    		virtual void Show()const;
    		friend ostream& operator<<(ostream& os, const Port& p);
    };
    class VintagePort: public Port{
    	private:
    		char* m_nickname;
    		int m_year;
    	public:
    		VintagePort();
    		VintagePort(const char* brand = "none", int bottles = 0, const char* nickname = "none", int year = 0);
    		VintagePort(const VintagePort& vp);
    		~VintagePort(){delete []m_nickname;};
    		VintagePort& operator=(const VintagePort& vp);
    		void Show()const{};
    		friend ostream& operator<<(ostream& os, const VintagePort& vp);
    };
    int main(){}
    
    
    Port::Port(const char* brand , const char* style , int bottles ){
    	m_brand = new char[strlen(brand)+1];
    	strcpy(m_brand, brand);
    	strncpy(m_style, style, 19);
    	m_style[19]='\0';
    	m_bottles = bottles;
    }
    Port::Port(const Port& p){
    	m_brand = new char[strlen(p.m_brand)+1];
    	strcpy(m_brand, p.m_brand);
    	strncpy(m_style, p.m_style, 19);
    	m_style[19]='\0';
    	m_bottles = p.m_bottles;
    }
    Port& Port::operator=(const Port& p){
    	if(this ==&p){
    		return *this;
    	}
    	delete m_brand;
    	m_brand = new char[strlen(p.m_brand)+1];
    	strcpy(m_brand, p.m_brand);
    	for (int i = 0; i<20; i++){
    		m_style[i]='\0';
    	}
    	strncpy(m_style, p.m_style, 19);
    	m_style[19]='\0';
    	m_bottles='\0';
    	m_bottles = p.m_bottles;
    	return *this;
    }
    Port& Port::operator+=(int b){
    	m_bottles +=b;
    }
    Port& Port::operator-=(int b){
    	if (m_bottles>=b){
    		m_bottles -=b;
    	} else
    	m_bottles = 0;
    }
    void Port::Show()const{
    cout<<"The brand is:"<<m_brand<<" of style:"<<m_style<<" and there are:"<<m_bottles<<" bottles in the collection"<<endl;
    }
    ostream& operator<<(ostream& os, const Port& p){
    	os<<"The brand is:"<<p.m_brand<<" of style:"<<p.m_style<<" and there are:"<<p.m_bottles<<" bottles in the collection"<<endl;
    	return os;
    }
    void Port::SetBrand(const char* brand){
    	m_brand = new char[strlen(brand)+1];
    	strcpy(m_brand, brand);
    }
    VintagePort::VintagePort(const char* brand, int bottles, const char* nickname, int year){
    	Port::SetBrand(brand);
    	Port::SetBottles(bottles);
    	m_nickname = new char[strlen(nickname)+1];
    	strcpy(m_nickname, nickname);
    	m_year = year;
    }
    VintagePort::VintagePort(const VintagePort& vp){
    	this->GetBrand()	=	new char [strlen(vp.Port::GetBrand())+1)]
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,852
    A better way of writing the VintagePort constructor would be to invoke the base class constructor:
    Code:
    VintagePort::VintagePort(const char* brand, int bottles, const char* nickname, int year) : Port(brand, "Vintage", bottles) {
        m_nickname = new char[strlen(nickname)+1];
        strcpy(m_nickname, nickname);
        m_year = year;
    }
    But why are you using manual memory management? m_nickname should be a std::string object. You can then change it to:
    Code:
    VintagePort::VintagePort(const char* brand, int bottles, const char* nickname, int year) : Port(brand, "Vintage", bottles) {
        m_nickname = nickname;
        m_year = year;
    }
    Assuming that you make this change, the copy constructor would then be:
    Code:
    VintagePort::VintagePort(const VintagePort& other) : Port(other.m_brand, other.m_style, other.m_bottles) {
        m_nickname = other.m_nickname;
        m_year = other.m_year;
    }
    You can then get rid of the copy assignment operator and destructor since the compiler generated ones will do.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Mar 2016
    Posts
    203
    Thanks, I did consider the member initializer list syntax but it felt like:
    (a) cheating to sneak in a style argument into the derived class when it's not defined in the problem and
    (b) redundant to keep calling VintagePort "Vintage"
    As mentioned in the OP the problem asks to use arrays but yes, strings would be much better of course.
    But you gave me a good idea to have another overloaded constructor in the base class that would mimic the signature of the derived class declaration and take it from there:
    Code:
    Port(const char* brand = "none", int bottles =0);
    Many thanks
    Last edited by sean_cantab; 05-26-2016 at 09:14 AM.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,852
    Quote Originally Posted by sean_cantab
    (a) cheating to sneak in a style argument into the derived class when it's not defined in the problem and
    You are not sneaking in a style argument into the derived class: you are invoking the base class constructor with its style argument.

    Quote Originally Posted by sean_cantab
    (b) redundant to keep calling VintagePort "Vintage"
    The Port class has a member named m_style. Therefore, whether you specify it or not, the base class subobject of the VintagePort object has a member named m_style. For some reason the Port class interface does not appear to have any way to obtain the value of this m_style member, except maybe the Show member function. This may be a sign of an oversight in the class design: probably the Port class should not have had m_style. But since it does have m_style and provides for it in the constructor, then it makes sense that VintagePort specify it to be "Vintage".

    Quote Originally Posted by sean_cantab
    But you gave me a good idea to have another overloaded constructor in the base class that would mimic the signature of the derived class declaration and take it from there:
    That would work. But if you want to denote styles by overriding, and you have such control over the base class, then you might as well get rid of the member named m_style.

    EDIT:
    Also, your implementation of the overloaded operator<< is wrong. Rather, this operator should forward its job to the virtual Show member function.
    Last edited by laserlight; 05-26-2016 at 09:20 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 04-27-2015, 05:40 AM
  2. constructors in derived class...
    By narendrav in forum C++ Programming
    Replies: 5
    Last Post: 12-20-2011, 03:34 PM
  3. Replies: 4
    Last Post: 12-29-2002, 12:29 AM
  4. Replies: 1
    Last Post: 12-11-2002, 10:31 PM
  5. Constructors + Derived class
    By MethodMan in forum C++ Programming
    Replies: 6
    Last Post: 11-10-2002, 05:05 PM

Tags for this Thread