4

I am making a set of derived classes for an assignment. I am instructed to use char arrays (c-strings). When I compile I keep getting the error:

Homework11.cpp: In function âint main()â:
Homework11.cpp:72: error: conversion from âchar [10]â to non-scalar type âBusinessâ requested
Homework11.cpp:73: error: conversion from âchar [10]â to non-scalar type âBusinessâ requested
Homework11.cpp:74: error: conversion from âchar [10]â to non-scalar type âAccountâ requested
Homework11.cpp:75: error: conversion from âchar [10]â to non-scalar type âAccountâ requested

I am fairly certain that my problem is originating up where I try to set the instance variable Name to the argument sent in. Here is my code with comments in where I believe the problems may be.

#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;

class Person{
public:
        Person() {}
        Person(char theName[]) {strcpy(name,theName);}
        void getName(char theName[]) // I think the problem may be here or in the line above
                { theName = name;}
private:
        char name[80];
 };

class Account : public Person{
public:
        Account() :accountNum(0),balance(0) {}
        Account(int actNo, char theName[])
                :Person(theName),accountNum(actNo),balance(0) {}
        void setBal(float theBalance)
                {balance = theBalance;}
        void deposit(float numDeposited)
                { balance = balance + numDeposited;}
        float withdraw(float numWithdrawn)
                { balance = balance -numWithdrawn;
                  return numWithdrawn;}
        float getBal() {return balance;}
        void printBal();
private:
        int accountNum;
        float balance;
};

 class Business : public Account{
 public:
        Business() : checkFee(0.0) {}
        Business(int actNo, char theName[])
                : Account(actNo, theName),checkFee(0.0) {}
        float withdraw(float numWithdrawn)
                {float newBalance = getBal()-numWithdrawn-checkFee;
                 setBal(newBalance);
                  return numWithdrawn;}
        void setFee(float fee) {checkFee = fee;}
 private:
        float checkFee;
};

void Account::printBal()
{
        char name[80];
        getName(name);
        cout<<setw(10)<<"Account # "<<accountNum<<setw(10)<<
              name<<setw(10)<<balance<<endl;
}


int main()
{
        char businessName1[10]="Business1";
        char businessName2[10] ="Business2";
        char regularName1[10] = "Regular1";
        char regularName2[10] = "Regular2";

       //The following 4 lines are the ones I am getting the error for
        Business bs1 = (1,businessName1);
        Business bs2 = (2,businessName2);
        Account rg1 = (1, regularName1);
        Account rg2 = (2, regularName2);

        cout<<"Intially: "<<endl;
        rg1.printBal();
        rg2.printBal();
        bs1.printBal();
        bs2.printBal();

        bs1.deposit(1000.00);
        bs2.deposit(1000.00);
        rg1.deposit(1000.00);
        rg2.deposit(1000.00);

        cout<<"----------------------------------------"<<endl;
       cout<<"After adding 1000.00 to all accounts:"<<endl;
        rg1.printBal();
        rg2.printBal();
         bs1.printBal();
        bs2.printBal();

        bs1.setFee(1.00);
        bs1.withdraw(500);
        bs2.withdraw(500);
        bs1.deposit(250);
        bs2.deposit(250);
        rg1.withdraw(500);
        rg2.deposit(500);

        cout<<"---------------------------------------"<<endl;
        cout<<"Finially:"<<endl;
        rg1.printBal();
        rg2.printBal();
        bs1.printBal();
        bs2.printBal();

        return 0;
}
Charles
  • 50,943
  • 13
  • 104
  • 142
art3m1sm00n
  • 389
  • 6
  • 9
  • 19

2 Answers2

10

The proper syntax would be Business bs1(1,businessName1);. If you want to use =, you can also use copy intialization Business bs2 = Business(2,businessName2);.

The former is known as direct initialization. They aren't exactly the same thing though, see Is there a difference in C++ between copy initialization and direct initialization? for in-depth information.

In Business bs1 = (1,businessName1); the 1 and array businessName1 are separated by the comma operator. The comma operator evaluates the first operand, i.e. 1 and throws away the results and returns the value of the second operand, which is an array in your case. In other words, your code is the equivalent of Business bs1 = businessName1;. This is why the error message says it cannot convert a char[10] to a Business object.

Community
  • 1
  • 1
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
1

Change the first line that produces an error to Business bs1(1,businessName1); and the rest similarly. That's the C++ idiom for initialization of a class instance on the stack.

Business bs2 = Business(2,businessName2); as suggested by Jesse Good is, I'd argue, a Java idiom that is poor practice in C++. It's slower because there are two implicit constructor calls and one copy constructor call, as opposed to the single constructor call in Business bs1(1,businessName1);. In this case there is another trap: you have not defined a copy constructor for the Business type, which means that the compiler will create one for you that does a shallow copy. bs2.name will end up a pointer to memory that isn't necessarily correctly freed when bs2 goes out of scope--a classic memory leak.

The corresponding C++ idiom is instead to construct a new object on the heap, then assign its address to a pointer: Business *bs2 = new Business(2,businessName2);.

There's another problem with your code. Generally, it's also bad style to assign arrays by name in C or C++ (and remember, statically allocated strings like char theName[] are just a special kind of array). Look at the definition of getName() in Person:

void getName(char theName[])
    { theName = name; }

This is assigning the array names (which are not exactly pointers, but close cousins), not copying the contents of one string to another. In printBal() you then write

char name[80];
getName(name);

When getName() executes it binds printBal()'s local variable name to the parameter theName. So far, so good, although the variable names you choose could be a little less confusing. :) But then the body of getName() executes and assigns the address of the private instance variable name to theName (which is the name of an array--again, a special kind of pointer). When getName() returns, there's no permanent change to the local variable name in printBal(). The correct way to write Person::getName() would be with strcpy(), the way you wrote the second Person constructor:

void getName(char theName[])
    { strcpy(theName,name); }
dodgethesteamroller
  • 1,272
  • 9
  • 12
  • This answer is incorrect. 1) Most likely the code will be optimized so that both forms are equivalent. 2) `name` is an **array**, not a pointer. The default copy constructor will be fine. – Jesse Good Apr 23 '13 at 22:28
  • 1. I don't think you can make such a sweeping statement. As the discussion at the link you gave above (_Is there a difference in C++ between copy initialization and direct initialization?_) shows, there are a lot of complicated edge cases and compilers can't reliably optimize out those copy constructor calls. I maintain that it's poor style. C++ isn't Java. 2. You're right, but I think relying on the default copy constructor is also poor C++ style; also see my edited answer for another related problem with the original code. – dodgethesteamroller Apr 23 '13 at 22:58
  • If you don't believe me, how about a [quote](http://en.wikipedia.org/wiki/Copy_elision#cite_note-moreexcept-2): `As a result, copy-initialization is usually equivalent to direct-initialization in terms of performance`. Note that the citation is from Herb Sutter's book `More Exceptional C++`. – Jesse Good Apr 23 '13 at 23:02
  • 1
    I stand corrected on the optimization question, but I maintain that the copy-initialization version is bad style. `Business bs2 = Business(2,businessName2);` still looks to me like somebody meant to declare a heap variable and forgot the splat and `new`. Why not use the traditional form and avoid confusion? – dodgethesteamroller Apr 23 '13 at 23:28