Проблема класса C++ CLI

----- привет, мир 2.cpp -----

// Hello, World 2.cpp : main project file.

#include "stdafx.h"
#include "hello.h"
#include <string>

using namespace System;
using namespace std;

int main(array<System::String ^> ^args)
{
    hello hi = new hello("Bob", "Blacksmith");
    Console::WriteLine(L"Hello, " + hi.getName + "!");
    return 0;
}

----- привет.ч -----

#include <string>
using namespace std;

#ifndef HELLO_H
#define HELLO_H

class hello
{
private:
    string _fname;
    string _lname;
    //hello() { } // private default constructor

public:
    hello(string fname, string lname);
    void SetName(string fname, string lname);
    string GetName();

};

#endif

----- привет.cpp -----

#include "stdafx.h"
#include "hello.h"
#include <string>
using namespace std;

hello::hello(string fname, string lname)
{
    SetName(fname, lname);
}

void hello::SetName(string fname, string lname)
{
    _fname = fname;
    _lname = lname;
}

string hello::getName()
{
    return _fname + _lname;
}

----- Ошибки -----

  • ------ Начата сборка: Проект: Hello, World 2, Конфигурация: Отладка Win32 ------
  • Привет, мир 2.cpp
  • Hello, World 2.cpp(12): ошибка C2440: «инициализация»: невозможно преобразовать «привет *» в «привет»
  • Ни один конструктор не мог принять исходный тип, или разрешение перегрузки конструктора было неоднозначным.
  • Hello, World 2.cpp(13): ошибка C2039: 'getName': не является членом 'hello'
  • \documents\visual studio 2010\projects\cpp\hello, world 2\hello, world 2\hello.h(8): см. объявление 'hello'
  • привет.cpp
  • hello.cpp(17): ошибка C2039: 'getName': не является членом 'hello'
  • \documents\visual studio 2010\projects\cpp\hello, world 2\hello, world 2\hello.h(8): см. объявление 'hello'
  • hello.cpp(19): ошибка C2065: '_fname': необъявленный идентификатор
  • hello.cpp(19): ошибка C2065: '_lname': необъявленный идентификатор
  • Генерация кода... ========== Сборка: 0 успешно, 1 не удалось, 0 обновлено, 0 пропущено ==========

person Will    schedule 05.07.2010    source источник


Ответы (6)


Сообщения об ошибках сообщают вам, где именно и в чем заключаются проблемы, хотя поначалу они могут немного пугать. Может быть, я могу помочь демистифицировать их немного:

Hello, World 2.cpp(12): ошибка C2440: «инициализация»: невозможно преобразовать «привет *» в «привет»

Это означает, что в строке 12 в Hello, World 2.cpp вы пытаетесь поместить указатель на hello (возврат из new) внутри hi, который не является типом указателя. Поскольку здесь вам не нужен динамически размещаемый объект, просто удалите файл new.

В ситуациях, когда вам нужен динамически размещаемый объект, вы должны изменить переменную hi на hello * и добавить соответствующий delete.

Hello, World 2.cpp(13): ошибка C2039: 'getName': не является членом 'hello'

C++ чувствителен к регистру. В одном файле у вас GetName, в другом getName. Выбери один.

hello.cpp(19): ошибка C2065: '_fname' : необъявленный идентификатор hello.cpp(19): ошибка C2065: '_lname' : необъявленный идентификатор

Строка 19 файла hello.cpp — это определение нижнего регистра getName. Поскольку getName не был объявлен в классе (см. предыдущую ошибку), компилятор понятия не имеет, что такое _fname или _lname. Эти ошибки исчезнут, как только первоначальные проблемы будут решены.

Изменить

См. Ответ @Sergey для некоторых других более общих наблюдений о том, что нужно исправить.

person Cogwheel    schedule 05.07.2010

Ключевое слово new создает указатель — если вы сделаете это таким образом, «привет» должно быть объявлено как hello*, или вы должны переписать объявление как:

hello hi(...);

Вторая ошибка как раз из-за чувствительности к регистру (getName, GetName).

person AJ.    schedule 05.07.2010

hello hi = new hello("William", "Dyson");  

Должно быть

hello* hi = new hello(...);   

Or

 hello hi("William", "Dyson");  ;

Console::WriteLine(L"Hello, " + hi.getName + "!");

Должно быть

Console::WriteLine(L"Hello, " + hi.getName() + "!");

Могут быть и другие неудачи, но я должен идти сейчас.

person InsertNickHere    schedule 05.07.2010
comment
LЗдравствуйте, ? Разве это не литерал широкой строки, который неявно приводится к Char*, а затем к System::String? - person Arafangion; 30.11.2011

Есть несколько ошибок.

  • Имена файлов с пробелами. Не критично, но может привести к проблемам
  • Console::WriteLine(L"Hello, " + hi.getName + "!");

это должно быть что-то вроде этого:

 string s("Hello, ");
 s += hi->getName();
 s += "!"
 Console::WriteLine(s);
  • удалить объекты, выделенные с помощью new: delete hi;

  • string hello::getName() должно быть string hello::GetName()

  • Никогда не используйте use namespace ... в заголовочных файлах

  • Включить другие файлы в защитный блок

person Sergey    schedule 05.07.2010

Если вы выделяете что-то с помощью new, вы должны вызывать delete после того, как оно вам больше не нужно.

Если вы хотите использовать сборщик мусора для очистки, вы должны объявить класс как ref class hello, а затем создать его экземпляр с помощью:

hello^ hi = gcnew hello(...);   
person codymanix    schedule 05.07.2010

Некоторые комментарии, которые, несомненно, будут опубликованы до того, как я закончу писать это:

  1. Поставьте вас на первое место
  2. пространство имен System подразумевает Managed C++. Если вы не знаете, что это такое, и думаете, что используете обычный C++, прочтите о printf и std::cout.
  3. Линия

    hello hi = new hello("William", "Dyson");

    должен прочесть

    hello hi("William", "Dyson"); or hello* hi = new hello("William", "Dyson");

    Первый создает объект в стеке (который будет автоматически уничтожен при выходе из области видимости. Второй создает указатель на объект в куче, который вам придется delete до того, как указатель выйдет из области видимости (после того, как вы я закончила с этим)

  4. по поводу hello::getName(): у вас есть опечатки по поводу заглавных букв (getname vs getName) и это должно быть объявлено так (в заголовке и соответственно в исходном файле):

    const string getName() const;

    Первый const является необязательным, но мне он нравится, последний позволяет вызывать эту функцию из объекта const hello и сообщает читателю, что функция не изменяет объект.

  5. Вы должны передать string по ссылке (вот правильный конструктор):

    hello( const string &fname, const string& lname);

  6. Исходники и заголовки должны иметь имена без пробелов (или специальных символов) в них, это будет проблематично для UNIX‹->Windows, если вы не будете осторожны.

Это все, что я вижу сейчас.

person rubenvb    schedule 05.07.2010
comment
Публичные члены первыми или нет — это всего лишь дело вкуса. И printf() не C++. - person codymanix; 05.07.2010
comment
Вы должны передавать строку по ссылке: это лучший совет, если строки не копируются внутри функции. Если вы планируете сделать копию, лучше сделать копию неявной (передавать по значению) и позволить компилятору выяснить, как лучше оптимизировать. - person Cogwheel; 05.07.2010
comment
@codymanix: согласен, но МНОГИЕ люди его используют. Я избегаю этого, как чумы. @ Зубчатое колесо: согласен, но не помешает выработать привычку передавать const ссылок как можно больше. - person rubenvb; 05.07.2010