If I have a baseclass Base and a subclass Sub, and in the subclass have a memberfunction that doesnt exist in the superclass - how do I tell the compiler its there?
#include <iostream>
using namespace std;
class Base {
public:
};
class Sub : public Base {
public:
void printFromSub() {
cout << "I am not inherited ;-)" << endl;
}
};
int main() {
Sub sub;
Base* base;
base = ⊂
base->printFromSub(); // not possible at compile-time
return 0;
}
You have to cast to derived class.
If you are sure that base points to an object of the derived class, then you can use static_cast.
static_cast<Sub*>(base)->printFromSub();
If you aren't sure, then you'll need a runtime check.
Sub* p = dynamic_cast<Sub*>(base);
if (p) p->printFromSub();
Related
I have a base class which serves as an interface (if I use that word correctly). The idea is that the base class has some derived classes that implement one virtual function of the base class. Then I also need another class that extends the base class (lets call it extended base). What I would like is that I can store a class derived from base into an extended base pointer.
MWE:
class Base {
public:
virtual ~Base();
virtual double value();
}
class Derived : public Base{
public:
double value() override {return 5;}
}
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase ();
virtual double value2(){return 10;}
}
int main() {
ExtendedBase * object;
object = new Derived();
std::cout << object->value(); //should give implementation in Derived, i.e. 5
std::cout << object->value2(); //should give implementation in ExtendedBase, i.e. 10
delete object;
return 0;
}
With this MWE I get a compile error at the second line in the main. error: cannot convert 'Derived*' to 'ExtendedBase*' in assignment object = new Derived();. Part of me understands why it doesn't work (although I can't explain), but I would like to know if I can get the desired behaviour in some other way.
P.S. Sorry about the bad question name, I couldn't think of another way to keep it short
P.S.2 I know raw pointers like this are not advised. In the future I will change to smart pointers but I don't think they are needed for this simple example
ExtendedBase and Derived are each derived from Base. If you want to use an ExtendedBase* pointer to point to a Derived object, you will need to derive Derived from ExtendedBase.
To use a different example,
class Feline{
virtual void run();
}
class Housecat : Feline{
void run() {}
}
class BigCat : Feline{
virtual void run();
virtual void roar();
}
Here Feline, Housecat, and BigCat are analogous to Base, Derived, and ExtendedBase. BigCat and Housecat are each Feline, but since Housecat is not a BigCat, you can't use a BigCat* pointer to point to a Housecat.
This is the desired behavior from a language architect perspective.
For instance, if you have
class Ship
{
public:
virtual void move() = 0;
}
class Steamboat : public Ship
{
public:
virtual void move() override { ... }
}
class Sailboat : public Ship
{
public:
virtual void move() override { ... }
virtual void setSails() { ... }
}
Now, you don't want a Steamboat to become a Sailboat all of a sudden, hence:
Steamboat* tootoo = new Sailboat;
cannot be valid.
That's why your code cannot work. Conceptually.
So giving a quick fix is not possible, because your concept is not really clear.
When you are assigning an address to a pointer that means you should be able to access all the members of the type the pointer is pointing to through the pointer.
For ex,
class B {};
class D : B {};
B *p = new D();
now through p, at least you can access all the members of base portion of the derived class.
But in your code,
ExtendedBase * object;
object = new Derived();
object should be able to access all the members of ExtendedBase portion of the derived class. But how is it possible as derived class is not derived from ExtendeBase. So compiler is throwing error.
You need to do some changes in your code to work.
To make base as interface (abstract class), you need to define at
least one member function as pure virtual.
If you want to access the member function of ExtendedBase through
Base pointer, you should define same function 'val' in your
ExtendedBase.
Below are the changes.
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {};
virtual double value() = 0;
};
class Derived : public Base{
public:
~Derived() {};
double value() {
return 5;
}
};
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase () {};
double value()
{
return 10;
}
};
int main() {
Base *p = new Derived();
std::cout << p->value() << std::endl;
delete p;
Base *p1 = new ExtendedBase();
std::cout << p1->value() << std::endl;
delete p1;
return 0;
}
I have a base class instance, there is a derived class that inherits from the base class, I want to transform the base instance into derived instance, (if possible without copying anything (maybe sending to the derived class a reference of the base class)) how can I achieve that?
Note: I need this because I'm using factory design pattern which identify the derived class needed to be created using a parameter located in the base instance.
//class A
//class B: public A (pure virtual)
//class C: public B
B BFactory::makeB(A &a) {
int n=a.getN();
if(n==1){
return new C();
}
}
Thanks.
Consider the case of the car.
You can treat a Lamborghini as a car.
You can treat a Yugo as a car.
You can treat a car as a Lamborghini if it is a Lamborghini. In C++ this means a pointer to car that really points to a Lamborghini. In order to get a Lamborghini pointer back out of the car pointer you should use dynamic_cast. If the car does not point to a Lamborghini, dynamic_cast will return NULL. This keeps you from trying to pass off a Yugo as a Lamborghini and blowing the Yugo's engine.
But when the Lamborghini is being treated as a car, it can only do car things. If you copy a Lamborghini into a car, you strip out all Lamborghini-ness forever. It's gone.
Code time!
This, I'm afraid cannot be done:
//class A
//class B: public A (pure virtual)
//class C: public B
B BFactory::makeB(A &a) {
int n=a.getN();
if(n==1){
return new C();
}
}
C is being copied into a B and the B is being returned. B would need a constructor that took a C, but the point is moot. B cannot be instantiated if it's pure virtual. For now we'll ignore the leak that would be new C()
Also can't use a reference for this job, pretty much the same problem, so you're trapped into returning a pointer
B * BFactory::makeB(A &a) {
int n=a.getN();
if(n==1){
return new C();
}
}
Now I'm going to make a suggestion: Build the make function into B and handle the case where A doesn't map to anything recognized by B.
class B: public A
{
public:
virtual ~B(){}
static B * makeB(A & a)
{
switch(a.getN())
{
case 1:
return new C();
}
return NULL;
}
};
But this leads to another recommendation: Why should B know anything? And What is the point of A at this level? Why is A storing build codes for classes two or more steps down the hierarchy? Bad from a maintenance point of view. The point of objects is they know who they are and how to manipulate themselves. Short-circuiting this leads to pain.
class B: public A
{
public:
virtual ~B(){}
virtual B* makeB() = 0;
};
Now B only makes Bs, needs no help from A, and those who extend B are stuck with figuring out how to make themselves--a task they should know better than anyone else. Much safer because there is never any possibility of a code unrecognised by B for a new class.
class C: public B
{
public:
B* makeB()
{
return new C();
}
};
class D: public B
{
public:
B* makeB()
{
return new D();
}
};
Edit: Traditional factory
You're asking for an abstract factory. For that you need nothing. You don't even need a class. You certainly don't need a class A. The goal of this sort of factory is the caller knows nothing about the class. By providing an A, the caller needs to know how to make an A or have another factory that makes an A.
First a bit of set-up in a header file BFactory.h:
#ifndef BFACTORY_H_
#define BFACTORY_H_
#include <exception>
class B
{
public:
virtual ~B(){}
virtual std::string whatAmI() = 0;
protected:
// data members common to all B subclasses
};
enum bType
{
gimmie_a_C,
gimmie_a_D,
gimmie_an_E
};
class BadTypeException: public std::exception
{
public:
const char* what() const noexcept
{
return "Dude! WTF?!?";
}
};
B* BFactory(enum bType type);
#endif /* BFACTORY_H_ */
Here I'm going to deviate from the book way a little. Rather than using an integer to identify the type to be built, I'm going to use an enum. Two reasons: Easier to read and understand gimme_a_C than 1 and generates a compiler error if you try to provide a value that is not enumerated.
enum bType
{
gimmie_a_C,
gimmie_a_D,
gimmie_an_E
};
And an exception to flag stupidity if the enum is updated with new types (gimmie_an_E) but the factory is not.
class BadTypeException: public std::exception
{
public:
const char* what() const noexcept
{
return "Dude! WTF?!?";
}
};
This is all the Factory client needs to see. They don't see C. They don't see D. They have no clue that C and D exist in any way other than the names listed in enum bType. All they ever see is pointers to B.
Now for the implementation BFactory.cpp:
#include "BFactory.h"
class C:public B
{
std::string whatAmI()
{
return "C";
}
};
class D:public B
{
std::string whatAmI()
{
return "D";
}
};
B* BFactory(enum bType type)
{
switch(type)
{
case gimmie_a_C:
return new C();
case gimmie_a_D:
return new C();
default:
throw BadTypeException();
}
}
I'll leave it up to the reader to spot the stupid bug in the above code that makes these error prone and why I don't like them.
And usage, main.cpp:
#include "BFactory.h"
int main()
{
B * temp;
temp = BFactory(gimmie_a_C);
std::cout << temp->whatAmI() << std::endl;
delete temp;
temp = BFactory(gimmie_a_D);
std::cout << temp->whatAmI() << std::endl;
delete temp;
//temp = BFactory(1001); // won't compile
try
{
temp = BFactory(gimmie_an_E); // will compile, throws exception
std::cout << temp->whatAmI() << std::endl;
}
catch(BadTypeException& wtf)
{
std::cerr << wtf.what() << std::endl;
}
}
There is still absolutely no use for or involvement of A. A if it exists, should no nothing about B or the children of B.
These days there is a little improvement we can make so that the pointers are a little safer. unique_ptr allows us to maintain the polymporphic advantages of a pointer to B without the memory management woes.
std::unique_ptr<B> BFactory(enum bType type)
{
switch(type)
{
case gimmie_a_C:
return std::unique_ptr<B>(new C());
case gimmie_a_D:
return std::unique_ptr<B>(new D());
default:
throw BadTypeException();
}
}
and the new main:
int main()
{
std::unique_ptr<B> temp;
temp = BFactory(gimmie_a_C);
std::cout << temp->whatAmI() << std::endl;
temp = BFactory(gimmie_a_D);
std::cout << temp->whatAmI() << std::endl;
}
You might want to define a constructor that takes the base class instance as the argument so you can later use static_cast to convert from the base class to the derived class.
class Derived : public Base
{
public:
Derived(const Base& base) : Base{base} {}
};
int main()
{
Base a;
Derived b = static_cast<Derived>(a);
}
If you want to create a derived class instance using the base class instance then there is some conversion rule between the two, which you can specify explicitly using a derived class constructor.
Although it is impossible to alter the type of an object you still can make instances of base and derived classes share the same data:
#include <memory>
#include <iostream>
class Base
{
protected:
struct CommonData
{
int A;
int B;
};
std::shared_ptr<CommonData> m_data;
public:
Base() : m_data(std::make_shared<CommonData>())
{
m_data->A = 0;
m_data->B = 0;
}
void SetData(Base * source)
{
m_data = source->m_data;
}
int A() const { return m_data->A; }
int B() const { return m_data->B; }
void SetA(int value) { m_data->A = value; }
void SetB(int value) { m_data->B = value; }
};
class Derived : public Base
{
public:
int C;
};
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Base base;
base.SetA(12);
base.SetB(46);
Derived derived;
derived.SetData(&base);
derived.C = 555;
cout << derived.A() << endl; // 12
cout << derived.C << endl; // 555;
cin.get();
}
A base class should not "know" about how to make its own derived class instances. That is the point of inheritance.
The "is a" relationship of derived classes means that any subclass instance will pass as a base class instance transparently, and you can treat it as one, and by default base class non-virtual methods are called on a base class reference, even if it a derived class instance. Only virtual methods use the derived class method.
In the case of creating a base class instance from a derived class you want to "slice" the instance data (normally a bad thing and normally a mistake).
class A{ // ... A stuff };
class B : A
{ // ... B stuff
A make_A() { return (A) B(*this); } // copy cast to A
};
Under no circumstances try to do this:
class B;
class A { // ...
B make_B() { return B(*this); }
};
That is inverted OO logic. It requires at least 2 scans of the source code, which C++ does not do. It fails.
How can someone implement this pattern:
class Base {//doesn't know anything about potential descendant-classes, like Child
public:
Base * foo( void) {
//some code
return ( Base *) new !Child-constructor!();
}
};
class Child : public Base { };
//—————————————————————————————————————————————————
#include <iostream>
#include <typeinfo>
using namespace std;
int main( void) {
Base * base_p = Child().f();
cout << typeid( *base_p).name(); //expected to get "Child"
return 0;
}
I can't find the right syntax for this type of constructions (calling the "potential" child constructor).
UPD: I forgot to mention (didn't think that there can be missunderstanding), that Child class must not be known in definition of Base. So I wanted foo to call the constructor of the class in which it's gonna be inherited.
"... that Child class must not be known in definition of Base. So I wanted foo to call the constructor of the class in which it's gonna be inherited."
IMHO the easiest way is to provide a templated factory function with Base
class Base {
public:
template<class Derived>
static std::unique_ptr<Base> foo( void) {
//some code
return std::unique_ptr<Base>(new Derived());
}
};
class Child : public Base {
public:
Child() {}
virtual ~Child() {}
};
int main() {
std::unique_ptr<Base> p = Base::foo<Child>();
return 0;
}
Check the compilable sample here please.
This design is awful, btw.
//terriblecode.hpp
struct Base
{
Base * foo(void);
};
struct Child : public Base{};
//terriblecode.cpp
Base* Base::foo() {return (Base*) new Child();}
The definition of child isn't needed untill the definition of foo. Separate your declaration from your definition of member functions, and it is pretty easy to do.
Just need to make sure you let the compiler know about your derived class before the first use:
class Child; // forward declaration
class Base {
public:
Base * foo( void);
};
class Child : public Base { };
// the function needs to be defined after the "Child" is known
Base * Base::foo( void) {
//some code
return new Child; // will be automatically type-cast to base class
}
//—————————————————————————————————————————————————
#include <iostream>
#include <typeinfo>
using namespace std;
int main( void) {
Base * base_p = Child().f();
cout << typeid( *base_p).name(); //expected to get "Child"
return 0;
}
However, I'd recommend a different pattern:
class Child; // forward declaration
class Base {
public:
static Base * foo( void); // static "factory" method
};
class Child : public Base { };
// the function needs to be defined after the "Child" is known
Base * Base::foo( void) {
//some code
return new Child; // will be automatically type-cast to base class
}
//—————————————————————————————————————————————————
#include <iostream>
#include <typeinfo>
using namespace std;
int main( void) {
Base * base_p = Base::f(); // use scope resolution, not object's method
cout << typeid( *base_p).name(); //expected to get "Child"
return 0;
}
Is there a way to determine the type of a child class with a baseclass pointer?
I have declared a pointer in a class constructor like this
in .h file
baseclass *screen;
in constructor
screen = new childclass();
Lets say baseclass has 5 different child classes and in my program I switch my pointer around to point towards various child objects, how can I determine the type of the object that screen is currently pointing towards?
Don't.
Use virtual dispatch to achieve different behaviours for different derived types.
You can compare typeid's: typeid(somepointer) == typeid(someclass) to find out what actual object was instantiated.
Here is how you could do it. But as many others have suggested, it's not the right way to do it. Derived classes should handle the different behaviors.
#include <iostream>
#include <typeinfo>
using namespace std;
class Base{
public:
virtual void func();
};
class Derived : public Base{
public:
virtual void func(){
return;
}
};
class AnotherDerived : public Base{
public:
virtual void func(){
return;
}
};
int main(){
Base *dp = new Derived;
Base *adp = new AnotherDerived;
cout << typeid(*dp).name() << endl;
cout << typeid(*adp).name() << endl;
return 0;
}
Starting from this code:
class Base{
public:
virtual void foo(){....}
};
class Derived{
public:
void foo(){....}
};
If d is a Derived object, can I in some way invoke the foo method defined in the Base class for this object?
Edit: i mean from the outside, such that d.foo() binds to Base::foo()
Specify it explicitly in the call.
#include <iostream>
class Base{
public:
virtual void foo(){
std::cout << "Base" << std::endl;
}
};
class Derived : public Base{
public:
void foo(){
std::cout << "Derived" << std::endl;
}
};
int main()
{
Derived d;
d.Base::foo();
return 0;
}
Just qualify the call (Assuming that Derived actually inherits from Base, which in your code it doesn't):
Derived d;
d.Base::foo();
Now, while this is doable, it is also quite questionable. If the method is virtual, it is meant to be overridden and users should not call a particular override, but the final-overrider, or else they risk breaking class invariants all the way through.
Consider that the implementation of Derived::foo did some extra work needed to hold some invariant, if users call Base::foo that extra work would not be done and the invariant is broken, leaving the object in an invalid state.
To call it from outside code, you can still explicitly qualify the name in the call:
#include <iostream>
#include <vector>
struct base {
virtual void do_something() { std::cout << "Base::do_something();\n"; }
};
struct derived : public base {
virtual void do_something() { std::cout << "derived::do_something();\n"; }
};
int main() {
derived d;
d.base::do_something();
return 0;
}
If you're using a pointer to the object, you'd change that to d->base::do_something();.