1

I have two class.

class A:

class B: public A
{
     //new function
     void setHint(...);
}

And have struct data.

typedef std::shared_ptr<A> window_ptr;
std::stack<window_ptr> m_windowsStack;
m_windowsStack.push(std::make_shared<A>("Hint"));
m_windowsStack.push(std::make_shared<B>("Game"));

And have function find in stack:

std::shared_ptr<A> WindowManager::findWindow(std::string title)
{
    ... return result;
}

And use function for find element in stack:

auto w = findWindow("Game"); //return element type B 
w->setHint(window);

But it turns out that function findWindow return type A. I get error "'class A' has no member named 'setHint' w->setHint(window);"

Do I need to declare setHint function in class A as virtual function? How do I make a variable to automatically understand that it is of type B?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Tipok
  • 675
  • 8
  • 26
  • 1
    Just cast the result, i.e. `auto w = findWindow("Game");` -> `auto w = static_cast(findWindow("Game"));` – George Jan 06 '17 at 08:33
  • 1
    `class A:` is an error, please write real code. Also I am not sure if you intended `setHint` to be a variadic function – M.M Jan 06 '17 at 08:35
  • @M.M class A: {} it's abstract class, my class big and there is a lot of unnecessary variables for this question \ functions. :) – Tipok Jan 06 '17 at 08:38

2 Answers2

5

Without understanding your entire project, I'd say the right solution is likely to add a virtual function in the base class.

class A {
 public:
  virtual void setHint(/*...*/) { /* some default implementation */}
  // or pure virtual
  virtual void setHint(/*...*/) = 0;

  virtual ~A() = default; // base class should have a virtual destructor
};

class B: public A {
 public:
  void setHint(/*...*/) override;
};

Alternatively, If you know for sure that the type pointed to the return value from findWindow is a B you can simply static_pointer_cast it down

auto w = std::static_pointer_cast<B>(findWindow("Game"));
w->setHint(window);

If you aren't sure, and A is a polymorphic type (having any virtual functions) you can dynamic_pointer_cast and check for null

if (auto w = std::dynamic_pointer_cast<B>(findWindow("Game"))) {
  w->setHint(window);
}
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
  • another option is `dynamic_cast(*w).setHint(window);` - this will throw an exception instead of undefined behaviour in case it is not the expected type – M.M Jan 06 '17 at 08:40
  • @M.M right, but not if OP is trying to not add virtual functions – Ryan Haining Jan 06 '17 at 08:41
  • He said in a comment to the question that A is an abstract class (implying it already contains virtual functions) – M.M Jan 06 '17 at 08:41
  • 1
    You might want to use [cast operators for `shared_ptr`](http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast) instead of casting the raw pointer stored. – Holt Jan 06 '17 at 08:51
  • @Holt indeed, that does eliminate the extra variable – Ryan Haining Jan 06 '17 at 08:58
2

Your choices are:

  1. Declare setHint virtual in class A

  2. Use dynamic_pointer_cast

Thus

auto w = std::dynamic_pointer_cast<B>(findWindow("Game"));
assert(w);  // Will be nullptr if cast fails.
w->setHint(window);