Reputation: 3145
I have a superclass called Animal
with a method called create
that does:
static Animal* Animal::create(const std::string& name)
{
Animal* newAnimal = new Animal();
newAnimal ->name = name;
return newAnimal;
}
Now I have a subclass called Dog
. I want to override the create
method from Animal
, but avoid copy and pasting the code that is already in there... I basically want this:
static Dog* Dog::create(const std::string& name)
{
Dog* newDog = Animal::create(name); // This is the line that I have trouble with.
newDog->type="dog";
}
As I mentioned above, I noticed that C++ doesn't do automatic casting - I come from Java background...
Anyways, I was wondering if this is an acceptable way to fix it and doesn't lead to more headache:
Dog *newDog = static_cast<Dog *>(Animal::create(name));
ADDITIONAL NOTE: So after reading all the comments and solutions, I guess everyone suggests using constructors. But imagine a case that you are not allowed to modify the Animal class, it has a create method and you want to extend that method. Maybe a more proper way to ask is that: Is it possible to extend the super class create method? Let me know if I am totally off - I am very very very new to c++ so maybe the question is just non-sense in c++ point of view...
Upvotes: 0
Views: 2101
Reputation: 66922
Usually the solution is to use constructors:
#include <string>
class animal {
public:
animal();
animal(std::string name, std::string type);
virtual ~animal();
private:
std::string name_;
std::string type_;
};
animal::animal()
:name_("unnamed"), type_("unknown")
{}
animal::animal(std::string name, std::string type)
:name_(std::move(name)),
type_(std::move(type))
{}
animal::~animal() {}
and then:
class dog : public animal{
public:
dog();
dog (std::string name);
virtual ~dog ();
};
dog::dog() :animal("","dog") {} //delegate to the animal default constructor
dog::dog(std::string name) :animal(std::move(name), "dog") {} //delegate again
dog::~dog() {}
and that's far easier to use:
int main() {
dog fido("fido"); //creates a dog on the stack, _very fast_
};
Upvotes: 1
Reputation: 8677
I would just use constructors and polymorphism.
class Animal
{
const std::string name;
public:
explicit Animal(const std::string &name) : name(name) {}
virtual ~Animal() {}
virtual std::string type() const = 0;
};
class Dog : public Animal
{
public:
explicit Dog(const std::string &name) : Animal(name) {}
virtual std::string type() const { return "dog"; }
};
If you really don't like the polymorphism for whatever reason, then add a type
data member in Animal
, and assign to it in the Dog::Dog
(Dog constructor).
I don't think you can do what you are trying to do without changing how Animal
s are created. Here's why.
First, here's what Animal::create
does.
sizeof Animal
bytes on heapAnimal
using that allocated chunk of memory.name
field.Animal
objectHere is what a Dog::create
function would need to do:
sizeof Dog
bytes on heapAnimal
portion of the new Dog
object. I think you are trying to reuse the Animal::create
function for this?type
fieldDog
objectThe problem is with step 2 of Dog::create
. Since Animal::create
allocates its own memory and you can't pass in a pointer to a Dog
, there is no way to get Animal::create
to operate on the memory you allocated in step 1.
That said, depending on the internals of Animal
and specifically if it is copyable, you may be able to hack it as follows, but I'm not sure it would work or even be well-defined
static Dog * Dog::create(static Dog* Dog::create(const std::string& name)
{
Animal *animalTmp = Animal::create(name);
Dog* newDog = new Dog(); // note that Animal::Animal() c-tor is probably called
*newDog = *animalTmp; // you have to be careful about which `operator=` is called here
delete animalTmp;
newDog->type="dog";
return newDog;
}
This is completely unmaintainable, ugly as hell, very brittle, and A TERRIBLE IDEA.
Upvotes: 3