2013-04-23 2 views
0

Я делаю набор производных классов для назначения. Мне поручено использовать массивы символов (c-строки). Когда я компилирую я получаю сообщение об ошибке:.Ошибка: преобразование в нескалярный тип

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 

Я довольно уверен, что моя проблема, происходящих там, где я пытаюсь установить экземпляр имя переменной аргумента отправленного в Вот мой код с комментариями в котором я что проблемы могут быть.

#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; 
} 

ответ

5

Правильный синтаксис будет Business bs1(1,businessName1);. Если вы хотите использовать =, вы также можете использовать процедуру копирования Business bs2 = Business(2,businessName2);.

Первый известен как прямая инициализация. Они не совсем то же самое, хотя, см. Is there a difference in C++ between copy initialization and direct initialization? для подробной информации.

В Business bs1 = (1,businessName1);1 и массив businessName1 разделены comma operator. Оператор запятой оценивает первый операнд, то есть 1, и отбрасывает результаты и возвращает значение второго операнда, который является массивом в вашем случае. Другими словами, ваш код эквивалентен Business bs1 = businessName1;. Вот почему сообщение об ошибке говорит, что он не может преобразовать char[10] в объект Business.

+0

о господи, дух! ничего себе, не могу поверить, что я это сделал. Благодаря! – art3m1sm00n

0

Измените первую строку, которая производит ошибку, до Business bs1(1,businessName1);, а остальное аналогичным образом. Это идиома C++ для инициализации экземпляра класса в стеке.

Business bs2 = Business(2,businessName2); как предложено Jesse Good, я бы сказал, Java-идиома, которая является плохой практикой на C++. Это медленнее, потому что есть два неявных вызова конструктора и один вызов конструктора экземпляра, в отличие от вызова одного конструктора в Business bs1(1,businessName1);. В этом случае есть еще одна ловушка: вы не определили конструктор копирования для типа Business, а это значит, что компилятор создаст для вас то, что делает мелкую копию. bs2.name будет содержать указатель на память, который не обязательно правильно высвобождается, когда bs2 выходит за пределы области - классическая утечка памяти.

Соответствующая идиома C++ вместо этого предназначена для создания нового объекта в куче, затем присваивает свой адрес указателю: Business *bs2 = new Business(2,businessName2);.

Есть еще одна проблема с вашим кодом. Как правило, это также плохой стиль для назначения массивов по имени на C или C++ (и помните, статически выделенные строки, такие как char theName[], представляют собой только особый вид массива). Посмотрите на определение getName() в Person:

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

Это присвоение имен массивов (которые не являются точно указатели, но близкие родственники), а не копировать содержимое одной строки в другую. В printBal() вы затем написать

char name[80]; 
getName(name); 

Когда getName() выполняет его связывает локальную переменную printBal() «s name параметру theName. Пока что так хорошо, хотя имена переменных, которые вы выбрали, могут быть немного менее запутанными. :) Но тогда тело getName() выполняет и присваивает адрес переменной частного экземпляра name до theName (который является именем массива - опять же, особым видом указателя).Когда возвращается getName(), нет постоянного изменения локальной переменной name в printBal(). Правильный способ написать Person::getName() бы с strcpy(), как вы написали второй Person конструктор:

void getName(char theName[]) 
    { strcpy(theName,name); } 
+0

Этот ответ неверен. 1) Скорее всего, код будет оптимизирован так, чтобы обе формы были эквивалентны. 2) 'name' является ** массивом **, а не указателем. Конструктор копии по умолчанию будет в порядке. –

+0

1. Я не думаю, что вы можете сделать такое резкое заявление. Поскольку обсуждение по ссылке, которую вы указали выше (_Is есть разница в C++ между инициализацией копирования и прямой инициализацией? _), Показывает, что существует множество сложных случаев кросс, и компиляторы не могут надежно оптимизировать эти вызовы конструктора копирования. Я утверждаю, что это плохой стиль. C++ - это не Java. 2. Вы правы, но я думаю, что полагаться на конструктор копии по умолчанию - это тоже плохой стиль C++; также см. мой отредактированный ответ для другой связанной проблемы с исходным кодом. – dodgethesteamroller

+0

Если вы мне не верите, как насчет [quote] (http://en.wikipedia.org/wiki/Copy_elision#cite_note-moreexcept-2): 'В результате, инициализация копирования обычно эквивалентна прямой -инициализация с точки зрения производительности. Обратите внимание, что цитата взята из книги Херба Саттера «Более исключительный C++». –