C++ - When to exactly use ->? Error: base operand of ‘->’ has non-pointer type ‘BaseBond’

11,117

Solution 1

It because this:

BaseBond* tradingBook[bondCount];

in the constructor constructs a scoped variable that hides tradingBook. change that whole line to:

tradingBook = new BaseBond*[bondCount];

and the line

BaseBond* tradingBook;

in the header to

BaseBond** tradingBook;

and it should work.

Solution 2

That's because tradingBook[i] is an object, not a pointer, since you are referring to the member variable tradingBook which is defined as TradingBook *tradingBook. So, use tradingBook[i]. instead of tradingBook[i]-> .

Solution 3

Dani is correct that you should declare and allocate an array of your base-type with:

BaseBond** tradingBook;
...
tradingBook = new BaseBond[bondCount];

(But if it's variable-sized and you will be appending and removing, you'll either need malloc() (painful) or else use an STL Vector(/whatever) instead of array. For simplicity, allocate the largest array you might reasonably need.)

Anyway, sounds like the compiler (and documentation) tell you 'BaseBond' is an abstract base class which cannot be directly instantiated (but it will have subclasses which can). Figure out which subclasses by reading the documentation or code examples (or link it here if you can't figure that out after reading). Either that or you're supposed to define your own subclass class MyInheritedBond (BaseBond) and implement whatever methods are pure virtual (i.e. whichever methods the compiler nags about):

class MyInheritedBond (BaseBond) {
    void PVfn1() { /* empty dummy implementation to satisfy the compiler */ }
    int  PVfn2(...) { return NULL; }
    ...
};
Share:
11,117
CHawk
Author by

CHawk

Been developing on and off since I was a kid. Jack of many languages, master of none. Currently being forced into the deep-end of the pool by being the primary programmer at https://triphappy.com

Updated on June 05, 2022

Comments

  • CHawk
    CHawk almost 2 years

    Getting some really confusing errors and not sure exactly why. Here is my code:

    //=====================WORKS=======================
    TradingBook::TradingBook(const char* yieldCurvePath, const char* bondPath)
    {
    //...Some stuff
        BaseBond* tradingBook[bondCount];
    
        for (int i=0; i < bondCount; i++)
        {
            tradingBook[i] = new CouponBond(bonds[i]);
    
            printf("Bond: %s\n"
               "  Price: %.3f\n"
               "  DV01: %.3f\n"
               "  Risk: %.3f\n", tradingBook[i]->getID(), tradingBook[i]->getPrice(), tradingBook[i]->getDV01(), tradingBook[i]->getRisk());
        }
    }
    
    //=================DOESNT WORK======================
    //Gives Error: base operand of ‘->’ has non-pointer type ‘BaseBond’
    void TradingBook::runAnalytics()
    {
        for (int i=0; i < bondCount; i++)
        {
            tradingBook[i]->calcPrice(tradingBook[i]->getYield());
            tradingBook[i]->calcDV01();
            tradingBook[i]->calcRisk();
    
            printf("Bond: %s\n"
                   "  Price: %.3f\n"
                   "  DV01: %.3f\n"
                   "  Risk: %.3f\n", tradingBook[i]->getID(), tradingBook[i]->getPrice(), tradingBook[i]->getDV01(), tradingBook[i]->getRisk());
        }
    }
    

    I get the error base operand of ‘->’ has non-pointer type ‘BaseBond’ at every instance of ->, but only in the runAnalytics() method. tradingBook is a public class variable. Why would it give me an error in the bottom method but not the constructor? I don't get it.

    I also tried changing all the tradingBook[i]->method() to tradingBook[i].method() in the 2nd method, but it gives me a segmentation fault so I figured that isn't right. Can anyone help me clear up my confusion?

    In case it is needed, here is the header file for TradingBook:

    class TradingBook
    {
        public:
            TradingBook(const char* yieldCurvePath, const char* bondPath);
            double getBenchmarkYield(short bPeriods) const;
    
            BaseBond* tradingBook;
            int treasuryCount;
            Treasury* yieldCurve;
            int bondCount;
            void runAnalytics();
    
    };
    

    BaseBond is an abstract class. It's children are CouponBond and ZeroCouponBond. tradingBook[i] is filled with both types. Here is the header for BaseBond:

    class BaseBond{
      public:
        virtual double getPrice() = 0;
        virtual double getYield() = 0;
        virtual short getPeriods() = 0;
        virtual char* getID() = 0;
        virtual double getDV01() = 0;
        virtual double getRisk() = 0;
        virtual char* getRateType() = 0;
        virtual void calcPrice(double nyield) = 0;
        virtual double calcPriceR(double nyield) const = 0;
        virtual void calcDV01() = 0;
        virtual void calcRisk() = 0;
    
    
    };
    

    Thank you in advance, stackOverFlow!

  • CHawk
    CHawk over 12 years
    If I change all the '->' to '.' I get a segmentation fault. I don't know if this matters but BaseBond is an abstract class. It's children are CouponBond and ZeroCouponBond. tradingBook[i] is filled with both types. I added the header file for BaseBond to the original post. Thanks for the help!
  • Nicol Bolas
    Nicol Bolas over 12 years
    @Insomnihack: You get a segmentation fault because your code has more than one problem in it. You fixed one (using . instead of ->), and uncovered another. You'll have to ask another question to get an answer to that issue.
  • Daniel
    Daniel over 12 years
    @NicolBolas: the problem is not that -> should be replaced with . but rather the tradingBook should be a double pointer and initialized in the constructor and not hidden.
  • CHawk
    CHawk over 12 years
    Dani: When I make the adjustments you stated, I get the following error: TradingBook.cc|23|error: cannot allocate an object of abstract type ‘BaseBond’ Thoughts?
  • smci
    smci over 12 years
    @Insomnihack: then 'BaseBond' is an abstract base class which cannot be directly instantiated (but it will have subclasses which can). Figure out which subclasses by reading the documentation or code examples (or link it here). Either that or you're supposed to define your own subclass 'class MyInheritedBond (BaseBond)' and implement whatever methods are pure virtual.
  • CHawk
    CHawk over 12 years
    Thank you! BaseBond is inherited by two subclasses: CouponBond and ZeroCouponBond. There are both mixed together in the array tradingBook. I realize that I made the scope of tradingBook strictly in the constructor in my original code. My question is, how can I make it global to the whole class? I cannot use the line tradingBook = new BaseBond[bondCount]; because BaseBond is abstract and cannot be initialized directly
  • Daniel
    Daniel over 12 years
    @Insomnihack: My mistake, it should be tradingBook = new BaseBond*[bondCount];, edited answer.