|
-
December 5th, 2003, 04:27 AM
#1
Polymorphism question - not working like I tought
Ok, since I`m from Java background I tried to do the following
like in the Java, at first. Consider the Java code:
Code:
public abstract class Animal
{
public abstract void makeVoice(); // no implementation
}
public class Dog implements Animal
{
// the implementation of abstract method
public void makeVoice()
{
System.out.println("WUF!");
}
}
now, I tried to convert the above:
Code:
class Animal
{
private:
protected:
public:
virtual ~Animal() {}
virtual void makeVoice() = 0;
};
class Dog : public Animal
{
private:
protected:
public:
~Dog() {}
void makeVoice() { cout<<"WOF!";}
}
All fine this far. Ok, I can do thefollowing with Java
Code:
Animal animal = new Dog();
animal.makeVoice(); // -> "WOF!"
but if I do it with C++
Code:
Animal *animal = new Dog();
animal->makeVoice(); // this won`t compile
----------
c:/djgpp/lang/cxx-v3/bits/stl_construct.h:78: cannot allocate an object of type
`Animal'
c:/djgpp/lang/cxx-v3/bits/stl_construct.h:78: since type `Animal' has
abstract virtual functions
-----------
....but I assigned the animal to of type Dog, which implements
the needed function.
What I`m doing wrong here?
-
December 5th, 2003, 04:34 AM
#2
Apart from a missing semicolon at the end of class Dog, I can't see anything wrong with this. Are you sure there are no other pure virtual functions in Animal that Dog doesn't implement?
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
December 5th, 2003, 04:59 AM
#3
Like Graham said the only thing, which I see wrong is the semicolon missing. Also you should ALWAYS make your destructors virtual.
-
December 5th, 2003, 05:07 AM
#4
yes, they are all implemented ( the animal example was just a similar case to my real implementation )
in my real code, I put "Animal" references to a vector, but the compiler says:
Code:
c:/djgpp/lang/cxx-v3/bits/stl_vector.h:579: cannot allocate an object of type 'Animal'
c:/djgpp/lang/cxx-v3/bits/stl_vector.h:579: since type `Animal' has abstract virtual functions
All abstract functions are implemented.
I can compile whitout any errors the 'Animal' and 'Dog' classes and I can use, for example, the 'Dog' class as such. But
when I use it like:
Code:
Animal *animal = new Dog();
animal->doStuff(); -> won`t compile ????
-
December 5th, 2003, 05:16 AM
#5
Originally posted by usmarine
Also you should ALWAYS make your destructors virtual.
Not really a must, virtual destructor is needed only when polymorphic behavior is needed by using the base class pointer. If there isn't a requirement for polymorphic behavior or you don't want people inherit from the class, it is alright not to declare the destructor virtual.
-
December 5th, 2003, 06:41 AM
#6
Originally posted by halmark6Z
I can compile whitout any errors the 'Animal' and 'Dog' classes and I can use, for example, the 'Dog' class as such. But
when I use it like:
Code:
Animal *animal = new Dog();
animal->doStuff(); -> won`t compile ????
If you have a problem compiling the code, it is imperative that you post the exact code you are having a problem with. The reason is that we have to guess what your new "doStuff" is, since we have no idea how it's declared in your classes. This just tends to lead to guesses, and others "filling in" code that may or may not be the cause of the compiling error.
For example, this code compiles and runs correctly, after I corrected the issue of using objects instead of pointers:
Code:
#include <iostream>
class Animal
{
private:
protected:
public:
virtual ~Animal() {}
virtual void makeVoice() = 0;
};
class Dog : public Animal
{
private:
protected:
public:
~Dog() {}
void makeVoice() { std::cout<<"WOF!";}
};
int main()
{
Animal* animal = new Dog();
animal->makeVoice();
delete animal;
}
Now are we to assume that this doesn't compile at your end, or is it something else you have introduced that doesn't compile?
Regards,
Paul McKenzie
-
December 5th, 2003, 07:45 AM
#7
you are right, the Aniamal code worked. I`ll format my code
and put it here ... just a moment ...
-
December 5th, 2003, 08:52 AM
#8
Just a note: the destructor as posted in the original is virtual - it's declared virtual in Animal, so is implicitly virtual in Dog (that was one of the things that I checked).
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
December 5th, 2003, 08:55 AM
#9
Paul: good spot - I completely missed the lack of a "*" on the declaration. I would have though that the compiler would have caught it, though... oh, well, maybe not.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
December 5th, 2003, 09:22 AM
#10
Graham you are wrong!
Just because the destructor is virtual in the abstract class does not mean it is in the inherited class. Try it an see. You will leak memory big time and this is a mistake which people make all of the time. That is why I said the destructor should always be virtual so this problem never occurs.
-
December 5th, 2003, 09:44 AM
#11
ISO C++ standard 12.4/7
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly- declared) is virtual.
(My emphasis).
It's your compiler that's wrong, I'm afraid
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
December 5th, 2003, 09:47 AM
#12
I think Graham is correct.
From the ISO C++ Standard, Section 12.4 Destructors,
paragraph 7 :
If a class has a base class with a virtual destructor, its
destructor (whether user- or implicitly- declared) is virtual.
-
December 5th, 2003, 09:50 AM
#13
Sorry, Graham beat me to it.
-
December 5th, 2003, 10:25 AM
#14
Code:
//////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_CUSTOMER
#define INCLUDED_CUSTOMER
#include <string>
#include <fstream>
using namespace std;
class Customer
{
protected:
string name;
string pid;
double debt;
public:
virtual ~Customer() {}
virtual void setName(string nam)
{
name = nam;
}
virtual string getName()
{
return name;
}
virtual void setPid(string p)
{
pid = p;
}
virtual string getPid()
{
return pid;
}
virtual void setDebt(double comp) = 0;
virtual double getDebt() = 0;
virtual void serialize(ofstream& file) = 0;
virtual void deSerialize(ifstream& file) = 0;
};
#endif
Code:
//////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_REGULARCUSTOMER
#define INCLUDED_REGULARCUSTOMER
#include "customer.hpp"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <cstdio>
using namespace std;
class RegularCustomer : public Customer
{
private:
int visit_times;
public:
RegularCustomer ()
{
visit_times= 0;
}
~RegularCustomer ()
{
}
void setVisits(int m)
{
visit_times = m;
}
int getVisits()
{
return visit_times;
}
virtual double getDebt()
{
return debt;
}
void setDebt(double d)
{
debt = d;
}
// write contents to given text file
void serialize(ofstream& file)
{
// bunc of lines, never any complaints from here
}
// load contents from file
void deSerialize(ifstream& file)
{
const int BUF_SIZE = 80;
try
{
char line[BUF_SIZE];
clearBuffer(line, BUF_SIZE);
double debt= 0.0;
int visit_t= 0;
if(file.is_open())
{
// check for the corrrect start tag
file.read(line, 1);
if(!line[0] == '@')
{
return;
}
// parse name
file.getline(line, BUF_SIZE, '#');
string name(line, BUF_SIZE);
// trim name
setName(name);
// parse pid
file.getline(line, BUF_SIZE, '#');
string pid(line, BUF_SIZE);
// trim pid
setPid(pid);
// parse debt
file.getline(line, BUF_SIZE, '#');
debt= atof(line);
setDebt(debt);
// parse months
file.getline(line, BUF_SIZE, '#');
visit_t = atoi(line);
setVisits(months);
}
}
catch(...)
{
}
}
};
#endif
[CODE]
#ifndef INCLUDED_PLATINUMCUSTOMER
#define INCLUDED_PLATINUMCUSTOMER
#include "RegularCustomer.hpp"
#include <string>
#include <sstream>
#include <iostream>
#include <cstdio>
using namespace std;
class PlatinumCustomer: public RegularCustomer
{
private:
double bonus;
double bonusLimit;
public:
PlatinumCustomer()
{
bonus = 0;
bonusLimit = 0;
}
~Salesman()
{
}
void setBonus(double bon)
{
bonus = bon;
}
double getBonus()
{
return bonus;
}
void setBonusLimit(double bonl)
{
bonusLimit = bonl;
}
double getBonusLimit()
{
return bonusLimit;
}
double getDebt()
{
return RegularCustomer::getDebt() * 0.95;
}
void serialize(ofstream& file)
{
// all goes fine here
}
void deSerialize(ifstream& file)
{
const int BUF_SIZE = 80;
try
{
char line[BUF_SIZE];
clearBuffer(line, BUF_SIZE);
double debt = 0.0;
double bon = 0.0;
double bonusL = 0.0;
int visits = 0;
if(file.is_open())
{
file.read(line, 1);
if(!line[0] == '@')
{
return;
}
// parse name
file.getline(line, BUF_SIZE, '#');
string name(line, BUF_SIZE);
// trim name
setName(name);
// parse pid
file.getline(line, BUF_SIZE, '#');
string pid(line, BUF_SIZE);
// trim pid
setPid(pid);
// parse debt
file.getline(line, BUF_SIZE, '#');
debt= atof(line);
setDebt(debt);
// parse visits
file.getline(line, BUF_SIZE, '#');
visits= atoi(line);
setVisits(visits);
// parse bonus
file.getline(line, BUF_SIZE, '#');
bon = atof(line);
setBonus(bon);
// parse bonus limit
file.getline(line, BUF_SIZE, '#');
bonusL = atof(line);
setBonusLimit(bonusL);
}
}
catch(...)
{
}
}
};
#endif
[CODE]
in the main program, I have a function:
Code:
vector<Employee> loadCustomers(const char* filename)
{
// the customers stored here
vector<Customer> customers;
ifstream datafile;
try
{
char line[80];
datafile.open(filename);
if(datafile.is_open())
{
do
{
datafile.getline(line, 80, '#');
// check for Customer start tag
if(line[0] == '@')
{
Customer *customer= NULL;
string temp(line,2);
// returns just an int, see below
switch(getObjectType(temp.c_str()))
{
case REGULAR:
customer= new RegularCustomer();
customer->deSerialize(datafile); // complains about this
break;
.....
.....
} // switch
if(customer!= NULL)
personel.push_back(*customer); // complains about this
ps. hopefully I didn`t left any typos but here`s the structure of the program
-
December 5th, 2003, 10:36 AM
#15
Which line gives the error??
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|