Eugene |
Отправлено: 03.06.2003, 09:28 |
|
Не зарегистрирован
|
Я создал класс, у которого определи оператор = и преобразование обекта этого класса к типу AnsiString
class aStringObject
{
private:
String myString;
public:
__fastcall aStringObject(void){};
operator String(void){return myString;};
aStringObject & operator= (String theString){myString = theString; return *this;};
}
Пример 1:
aStringObject a;
AnsiString b="Test string";
//Как написанно в книгах неявный вызов оператора =
a=b;
//эквивалентен явному вызову: a.operator=(; те myString стало ="Test string"
Этот оператор = и operator String работают, если объект aStringObject создается статически как в примере 1.
Пример2(когда объект создается динамически):
aStringObject * a=new aStringObject;
AnsiString b="Test string";
//То неявный вызов оператора =
a=b;
//эквивалентен явному вызову: a.operator=(; что приводит к ошибке, так как надо a->operator=(;
Как сделать, чтобы работал пример2, то есть член-данное myString объекта a стало равно b, то есть "Test string".
|
|
Георгий |
Отправлено: 03.06.2003, 11:14 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
aStringObject* — это не тоже самое, что aStringObject — это разные обьекты.
придётся разъименовывать aStringObject* и получать aStringObject
Отредактировано Георгий — 3 Jun 2003, 11:17 |
|
Eugene |
Отправлено: 04.06.2003, 07:20 |
|
Не зарегистрирован
|
QUOTE (Георгий @ 3 Jun 2003, 11:14) | aStringObject* — это не тоже самое, что aStringObject — это разные обьекты.
придётся разъименовывать aStringObject* и получать aStringObject
|
А нельзя ли определить как-нибудь оператор = для указателя на объект, чтобы оставить код в виде
|
|
Alexander |
Отправлено: 04.06.2003, 12:57 |
|
Не зарегистрирован
|
Напиши, если так уж хочется:
[CODE]
AStringObject &a, *pa = new AStringObject;
a = *pa;
a = b;
[CODE] |
|
Георгий |
Отправлено: 04.06.2003, 14:06 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
адрес обьекта — это встроенный тип данных, который может использоватья как LValue только когда RValue может быть интерпретировано как адрес обьекта того же типа. Перегрузить оператор присваивания этого типа данных не представляется возможнам т.к. его описание как таковое отсутствует.
но если нужно динамическое создание экземпляра обьекта, то можно воспользоваться ссылками:
CODE |
class aStringObject
{
protected:
AnsiString myString;
public:
aStringObject(void)
{
Form1->Memo1->Lines->Add("aStringObject");
};
~aStringObject(void)
{
Form1->Memo1->Lines->Add("~aStringObject");
};
aStringObject& operator=(AnsiString& newString)
{
this->myString=newString;
return *this;
};
operator AnsiString(void)
{
return this->myString;
};
};
void __fastcall TForm1::Button1Click(TObject *Sender)
{
aStringObject asoStr;
AnsiString str2="asd";
str2=asoStr=str2;
//динамическое создание обьекта
aStringObject &asoDynamicStr=*new aStringObject;
str2=asoDynamicStr=str2;
//освобождение памяти от него
delete &asoDynamicStr;
}
|
|
|
Eugene |
Отправлено: 05.06.2003, 10:44 |
|
Не зарегистрирован
|
А как сделать, чтобы объект типа aStringObject (создаваемый динамически) был член-данным какого-то класса при обеспечении вызова операторов = и AnsiStinrg.
Если класс описать так:
CODE |
class MyClass
{
public:
aStringObject * DataString;
__fastcall MyClass()
{
DataString = new aStringObject;
};
__fastcall ~MyClass(void){delete DataString;};
};
|
то использовать операторы можно так
CODE |
MyClass * ClassObject = new MyClass();
String Str="Test string";
ClassObject->DataString->operator=(Str);
this->Edit1->Text=ClassObject->DataString->operator String();
delete ClassObject;
или
MyClass * ClassObject = new MyClass();
String Str="Test string";
*ClassObject->DataString=Str;
this->Edit1->Text=*ClassObject->DataString;
delete ClassObject;
|
Оба варианта использования операторов по-моему корявые
При попытке описать класс MyClass как
CODE |
class MyClass
{
public:
aStringObject & DataString;
__fastcall MyClass(void)
{
DataString = * new aStringObject;
};
__fastcall ~MyClass(void){delete &DataString;};
};
|
CBuilder ругается на первую скобку "{" конструктора MyClass():
[С++ Error] Reference member 'DataString' is not initialized.
В хелпере на эту ошибку написанно:
References must always be initialized, in the constructor for the class.
Вопрос: как сделать, чтобы работал код
CODE |
MyClass * ClassObject = new MyClass();
String Str="Test string";
ClassObject->DataString=Str;
this->Edit1->Text=ClassObject->DataString;
delete ClassObject;
|
|
|
Георгий |
Отправлено: 05.06.2003, 14:30 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
смутное подозрение, что Вы бьётесь головой об стену...
Давайте уточним ряд вещей:
1. Язык C++ позволяет создавать свои типы данных и использовать их также, как и встроенные
2. Создание обьекта — это не самоцель — обьекты создают, чтобы перейти на другой уровень абстракций, с целью уменьшения сложности задачи (разделяй и властвуй).
хорошо предположим, что Вам понадобилось, ради каких-то неведомых целей, сделать обьект у которого есть поле, содержащее другой обьект — вполне нормальная ситуация. Можно сделать:
1. поле — объект
2. поле — адрес объекта (указатель или ссылка)
функционально эти варианты эквивалентны, но есть небольшие различия:
если нескользо объектов должны совместно владеть одним объектом, то придётся использовать адрес объекта в качестве поля.
если в поле должен храниться неизвестный потомок некоторого обьекта, то тут опять придётся использовать поле адрес.
во всех остальных случаях нет смысла использовать поле адрес.
по поводу ссылок — это замена указателям в некоторых случаях, но не более. Ссылки имеет смысл использовать при передаче в функции больших объектов и всё — в остальных случаях использование указателей позволяет более ясно представлять механизмы работы программы.
в Вашем случае самым разумным будет такая структура объекта:
CODE |
class MyClass
{
public:
aStringObject DataString;
__fastcall MyClass();
__fastcall ~MyClass(void);
};
|
причём Ваш кусок кода будет работать
CODE |
MyClass * ClassObject = new MyClass();
String Str="Test string";
ClassObject->DataString=Str;
this->Edit1->Text=ClassObject->DataString;
delete ClassObject;
|
Кстати — я не очень понимаю, зачем вы указали, что конструктор и деструктор используют соглашение __fastcall — в этом случае часть аргументов передаётся через регистры общего назначения и это уменьшает время вызова этих функций, но конструктор и деструктор вызываются относительно редко — и этот __fastcall не даст никакого увеличения скорости работы.
забыл сказать как поле ссылку обьекта проинициализировать:
CODE |
class MyClass
{
public:
aStringObject & DataString;
MyClass(void);
~MyClass(void);
};
MyClass::MyClass(void):DataString(*new aStringObject)
{
};
MyClass::~MyClass(void)
{
delete &DataString;
};
|
Отредактировано Георгий — 6 Jun 2003, 01:46 |
|
Eugene |
Отправлено: 09.06.2003, 08:49 |
|
Не зарегистрирован
|
Цель моих вопросов — создать свойство вместе с редактором этого свойства.
Для использования редактора надо, чтобы это свойство было VCL классом (получается что-то вроде aStringObject, только унаследованное от TPersistent).
А объекты VCL классов можно создать только динамически.
С другой стороны я хочу обеспечить простой доступ к этому свойству для программиста как будто это свойство типа String(или др.) без каких-либо внутренних член-данных у этого свойства.
Вопрос: можно ли создать у компоненты свойство — ссылку (на тип aStringObject)?
|
|
Георгий |
Отправлено: 13.06.2003, 18:14 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
можно сделать свойство, которое работает с ссылкой:
CODE |
class aStringObject
{
protected:
AnsiString myString;
public:
aStringObject (const AnsiString& s)
{
this->myString=s;
};
aStringObject(void)
{
};
~aStringObject(void)
{
};
aStringObject& operator=(AnsiString& newString)
{
this->myString=newString;
return *this;
};
operator AnsiString(void)
{
return this->myString;
};
};
class MyClass
{
public:
MyClass(void);
~MyClass(void);
__property aStringObject MyString = { read=GetMyString, write=SetMyString };
private:
aStringObject & DataString;
void __fastcall SetMyString(aStringObject& value);
aStringObject& __fastcall GetMyString();
};
MyClass::MyClass(void):DataString(*new aStringObject)
{
};
MyClass::~MyClass(void)
{
delete &DataString;
};
void __fastcall MyClass::SetMyString(aStringObject& value)
{
this->MyString=value;
}
aStringObject& __fastcall MyClass::GetMyString()
{
return this->MyString;
}
|
и работает такой код:
CODE |
MyClass a;
AnsiString str="test";
a.MyString=str;
str=a.MyString;
|
это то, чего ты добивался?
кстати — в этом случае не обязательно использовать поле-ссылку — для поля указателя можно в методах Get и Set написать так:
CODE |
void __fastcall MyClass::SetMyString(aStringObject& value)
{
(*this->MyString)=value;
}
aStringObject& __fastcall MyClass::GetMyString()
{
return *this->MyString;
}
|
|
|
Eugene |
Отправлено: 14.06.2003, 11:42 |
|
Не зарегистрирован
|
Как я сказал выше, на самом деле класс aStringObject является унаследованным от TPersistent, то есть VCL классом.
Это приводит к тому, что при определении свойства этого типа как
CODE |
class MyClass
{
public:
MyClass(void);
~MyClass(void);
__property aStringObject MyString = { read=GetMyString, write=SetMyString };
private:
aStringObject & DataString;
void __fastcall SetMyString(aStringObject& value);
aStringObject& __fastcall GetMyString();
};
|
приводит к ошибке в строке объявления свойства: Объект класса VCL должен создаваться используя оператор new. (VCL style classes must be constructed using operator new).
Объявление свойства как указателя на aStringObject мне не подходит.
При объявлении свойства как ссылки приводит к ошибке :
Parameter mismatch in write access specifier of property MyString.
Хотя я описал все возможные методы записи:
CODE |
void __fastcall SetMyString(aStringObject & Value){this->DataString=Value;}
void __fastcall SetMyString(aStringObject Value){this->DataString=Value;}
void __fastcall SetMyString(aStringObject * Value){this->DataString=*Value;}
|
Использование прямого доступа к полю-ссылки DataString для записи
CODE |
__property aStringObject MyString = { read=GetMyString, write=DataString };
|
не приводит к ошибке на этапе компиляции и сборки.
Однако записать в свойство MyString не получается (в отличие от чтения):
CODE |
TMyClass * ClassObject=new TMyClass();
ClassObject->MyString=String("Data");
Edit1->Text=ClassObject->MyString;
delete ClassObject;
|
Вопрос: можно ли создать у MyClass работающую свойство — ссылку (на тип aStringObject) и как? Или придется использовать свойство-указатель MyString для вызова редактора этого свойства из Object Inspector`а, а для "простого" доступа сделать член-данное aStringObject & DataString как public?
Вопрос о ссылках.
CODE |
int Value1=1, Value2=2;
int & Value3=Value1;
|
Можно ли после такого объявление и определения ссылки Value3 сделать так, чтобы Value3 ссылался на Value2. |
|
Георгий |
Отправлено: 14.06.2003, 16:09 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
все VCL-обьекты — сделаны со свойствами-указателями, возможно именно из-за невозможности сделать иначе. Советую оставить свойство указатель, чтоб пользователи работали только с ним т.к. если они взялись за C++, то и с указателями должны свободно работать.
Можно ли после такого объявление и определения ссылки Value3 сделать так, чтобы Value3 ссылался на Value2.
Можно, но именно для этой последовательности обьявления переменных:
CODE |
int Value1=1, Value2=2;
int & Value3=Value1;
*((void**)(&Value2)-1)=&Value2;//получаем настоящий адрес переменной ссылочного типа и записываем в него адрес Value2, после чего Value3 ссылается на Value2
|
код надо будет корректировать в зависимости от платформы (направление роста стека) размещения переменных в стеке и особенностей этого размещения. Но при использовании одной платформы (i386) и одного компилятора (bc) всё будет в порядке. |
|