3
votes

I have a base class Base, and few derived classes: Derived1, Derived2 and Derived3.

I would like to have Function funcOne in all of them so i could regularly access it like this:

Base* d1 = new Derived1();
Base* d2 = new Derived2();
Base* d3 = new Derived3();

d1->funcOne();
d2->funcOne();
d3->funcOne();

but i would like to have Function funcTwo ONLY in Derived1 class. The issue is, i want to access it like that:

d1->funcTwo();

Is it possible to do it in some way other than creating a virtual funcTwo in the base class with an implementation of some kind, for example

void funcTwo(){ cout << "There is no funcTwo for this class" << endl; }

And other implementation only for the Derived1 class?

Thanks!

5
No this is not possible, anything you do via a pointer to Base must be part of Base's definition. The best you can do is to have the function call compile successfully, but do nothing at runtime if it is not a Derived1.M.M
Why can't you just declare d1 to be a Derived1 *? i.e. Derived1* d1 = new Derived1() instead of your current declaration.davmac
You have told us about the solution you want to have, but you haven't told us what problem you are trying to solve. There might be other, and even better, solutions if we only knew about the problem. Please read about the XY problem.Some programmer dude
@davmac - To be clear, of course i could just define it as Derived1* but i want all the objects in my program to be a Base class pointers so there is no such option.argamanza
You most likely have a design problem :)Drax

5 Answers

4
votes

You have two main options I can think of.

You could implement a virtual funcTwo in the base class as outlined in your question. This is generally bad practice as presumably funcTwo does not make sense in the context of Base, Derived2 and Derived3. It is better if a misuse of the API does not compile rather than just throw an error or, worse, silently fail. This looks like:

class Base() {virtual void funcTwo() {throw runtime_error("This should not be called");};
Base *d1 = new Derived1;
Base *d2 = new Derived2;
d1->funcTwo(); //fine
d2->funcTwo(); //compiles even though it doesn't make semantic sense, throws an exception

Alternatively, you could just implement funcTwo in Derived1. You would then try and hold pointers directly to Derived1 when possible and use dynamic_cast when not possible. This is preferable as direct calls to Base::funcTwo would fail to compile and you get semantics closer to what you are actually trying to express.

Base *b = new Derived1;
Derived1 *d1 = new Derived1;
Base *d2 = new Derived2;
d1->funcTwo(); //fine
if ((d1 = dynamic_cast<Derived1*>(b)) d1->funcTwo(); //fine
if ((d1 = dynamic_cast<Derived1*>(d2)) d1->funcTwo(); //funcTwo is not called, no errors
b->funcTwo(); //fails to compile
1
votes

Is it possible to do it in some way other than creating a virtual funcTwo in the base class [...]

Not if you want to treat all pointers uniformly, as Base* type.

That is, you could do this:

Derived1 *d1 = new Derived1(); // not treated as a base*
Base* b1 = d1;
Base* b2 = new Derived2();
Base* b3 = new Derived3();

d1->funcTwo(); // not treated as a base*
b1->funcOne();
b2->funcOne();
b3->funcOne();

You could also dynamic cast your pointers (but that's a worse solution than my code above):

void CallFunc2(Base* b) {
    if(auto d = dynamic_cast<Derived1*>(b))
        d->funcTwo();
}

Client code:

Base* b1 = new Derived1();
Base* b2 = new Derived2();
Base* b3 = new Derived3();
CallFunc2(b1); // will call Derived1::funcTwo
CallFunc2(b2); // will do nothing
CallFunc2(b3); // will do nothing
0
votes

Yes, you have dynamic_cast for that purpose. If your Base pointer is a Derived1 the cast will work and then you can call funcTwo(). If it isn't the cast will fail.

Using dynamic_cast is a design flaw most of the time. It is useful for some things like component loading and versioning where you don't know which version of a component is being loaded so you check to see whether it supports newer functionality.

In your case it is probably wrong.

Anyway if you do have to do it.

Base * b = getBasePtr(); // I don't know which one I got
Derived1 * d1 = dynamic_cast< Derived1 * >( b );
if( d1 )
    d1->func2();
0
votes

If you don't want the member function to be in Base at all, you could downcast the pointer to the correct class that have the function, using static_cast:

Base* b = new Derived;
static_cast<Derived*>(b)->func2();  // Call function only available in `Derived`

Of course, this requires that the pointer b is really a pointer to a Derived instance, or you have undefined behavior.

Note: Having downcasts like this, and doing different thing depending on the type of something, is usually considered bad design.

-1
votes

I think your best bet is to use a static method to try to do the resolution for you and execute functions that exist only in your derived classes.

class Base {
public:
  virtual ~Base() {}
  virtual void func1() = 0;
};

class Derived1 : public Base {
public:
  virtual ~Derived1() {}
  virtual void func1() { std::cout << "Derived1::func1" << std::endl; }
  void func2() { std::cout << "Derived1::func2" << std::endl; }
};

class Derived2 : public Base {
public:
  virtual ~Derived2() {}
  virtual void func1() { std::cout << "Derived2::func1" << std::endl; }
};

void func2(Base& b) {
  Derived1* d = dynamic_cast<Derived1*>(&b);
  if (d) d->func2();
}


void f() {
  Base* b1 = new Derived1;
  Base* b2 = new Derived2;

  func2(*b1);
  func2(*b2);
}

This approach will cost you a dynamic_cast, but save you a vtable lookup and will also provide you the desired behavior you were looking for.