0

I'm trying to get my base class currency. To access and return the string from it's derived class pound. My instructor specifically said it's a non public type (so I'm assuming a protected member would be the best here) and to NOT declare it in the base class. I'm having trouble making a function string getCurtype()to return the string and friending the derived class pound in my base class isn't not dong what I'm expecting it to do.

I'm guessing friending my derived class to the base class, doesn't give it access to it's protected members as it's only accisble in the derived class pound? Can someone please suggest me a way to set a getter string getCurType()for my string currencyType = "dollar" as a protected member in my derived class pound?

class currency{
 friend class pound;
 string getCurType(){return currencyType;};
 void print(){
    cout << "You have " << getPound() << " " << getCurType() << endl;
}
class pound : public currency{
protected:
   string currencyType = "pound";
}

Error:

test.cpp:11:34: error: 'currencyType' was not declared in this scope
        string getString(){return currencyType;};
                                  ^~~~~~~~~~~~
test.cpp:11:34: note: suggested alternative: 'currency'
        string getString(){return currencyType;};
                                  ^~~~~~~~~~~~
                                  currency
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • 2
    That is a wrong design. Rethink and refactor it. And the answer is "no" – A M Jul 20 '22 at 08:59
  • Aside: `getDollar()` is a pretty bad name for the amount of a currency, maybe you should change that to `getAmount()`? – Caleth Jul 20 '22 at 09:41
  • please do not change the question after you got answers. Please do not incorporate answers into the question. As it stands now the answers make no sense, because they refer to code that is not present in the qeustion anymore. I will rollback your edit – 463035818_is_not_an_ai Jul 20 '22 at 09:44

3 Answers3

3

Your design is backwards. Base classes should not need to know about derived classes other than the interface defined in the base. Define the interface you want to use in the base:

class currency{
public:    
    virtual string getCurType() = 0;       
    void print(){
        cout << "You have " << getCurType() << endl;
    }
};

class pound : public currency{
     string currencyType = "pound";
public:
     string getCurType() { return currencyType; }  
};
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • and possibly `virtual int getAmount() = 0` – Caleth Jul 20 '22 at 09:11
  • @Caleth its also missing in OPs code, so I just removed it. – 463035818_is_not_an_ai Jul 20 '22 at 09:12
  • 2
    @Caleth and it doesnt necessarily need to be virtual. depends... – 463035818_is_not_an_ai Jul 20 '22 at 09:16
  • I've included more of my code in my main post. I'm getting a different error now – pancakex62 Jul 20 '22 at 09:30
  • @pancakex62 I dont know what errors you have in `main` when I don't see the code. Note that your question should have contained a [mcve] from the start. Then I could have fixed also other errors. But please do not change the question now, as there are already answers. You can open another question or show me the code, eg here: https://godbolt.org/ – 463035818_is_not_an_ai Jul 20 '22 at 09:30
  • @Pancakex62 you cannot create an instance of `currency` because it is abstract. But you want an object of type `pound` anyhow. Also you should not name a variable same name as the class. Then it works as expected: https://godbolt.org/z/s7xqvsGx5 – 463035818_is_not_an_ai Jul 20 '22 at 09:34
2

You have misunderstanding here. To use currencyType in your base class it needs to be defined in that class. So in your case I would make the methods abstract in the abse class and implement it in the derived classes:

#include <iostream>
#include <string>

// this is your abstract base class (interface)
class currency
{
public:
    virtual std::string getCurType() const = 0;
    virtual void print() const = 0;
};

// implementation of pound
class pound : public currency
{
public:
    virtual std::string getCurType() const override
    {
        return "pound";
    }
    virtual void print() const override
    {
        std::cout << "You have " << getPound() << " " << getCurType() << std::endl;
    } 

private:
    int getPound() const 
    {
        return 3;
    }
};
RoQuOTriX
  • 2,871
  • 14
  • 25
0

I don't know if this is what your instructure is aiming for, but there is another way in C++ to access derived class's functions in a base class. It is called CRTP (curiously recurring template pattern)

In this approach, you access things in the base class, that are not defined in it, but only in derived classes. To enable this, you use a templated base class, that is instantiated with the derived class.

Your problem could be solved like this:

template<class T>
class currency {
public:
  string getCurType() { 
    // Convert this to a derived type, and call what you need
    return static_cast<T*>(this)->currencyType;
  }
};

// CRTP: Curiously, the template recurs...
class pound : public currency<pound>
{
public:
  string currencyType = "pound";
};

However, this requires the called derived thing to be public. To make it protected (or even private), you must friend the Base class:

class pound : public currency<pound> 
{
private:
  string currencyType = "pound";
  friend class currency<pound>;
};

But there is another more sophisticated approach, that does not require public or friended members, only protected. Via an intermediate accessor (see this article, found via this answer):

template<class T>
class currency
{
public:
  string getCurType() {
    return accessor::get_currencyType(derived());
  }

private:
  // Helper for cleaner code
  T &derived() {
    return *static_cast<T*>(this);
  }

  struct accessor : public T {
    // This accessor is derived from the derived class!
    static string get_currencyType(T &t) {
      // C++ Standard prohibits direct access to protected members here.
      // But it allows indirect access via pointer to member
      auto access = &accessor::currencyType;
      return t.*access;
    }
  };
};
king_nak
  • 11,313
  • 33
  • 58