OOP (C++). Манипулирование объектами без ссылок.
1699
7
Поручик Голицын
шатун сибирский обыкновенный
Долго думал, как озаглавить топик, никак не мог сформулировать...
В общем, суть вопроса:
как добиться того, чтобы с объектами можно было работать без помощи указателей и ссылок?
Пример:
MFC-шный класс CString.
Могу объявить любую функцию
int f(CString str){
// что угодно.
}
Аргумент в функции объявляется именно CString str, а не CString& str или CString* str.
Соответственно, могу объявить функцию
CString g(){ // не CString&, не CString*
CString temp;
// some manipulations with "temp"
return temp;
} - и все будет нормально.
Как сделать такое с произвольным классом?
В общем, суть вопроса:
как добиться того, чтобы с объектами можно было работать без помощи указателей и ссылок?
Пример:
MFC-шный класс CString.
Могу объявить любую функцию
int f(CString str){
// что угодно.
}
Аргумент в функции объявляется именно CString str, а не CString& str или CString* str.
Соответственно, могу объявить функцию
CString g(){ // не CString&, не CString*
CString temp;
// some manipulations with "temp"
return temp;
} - и все будет нормально.
Как сделать такое с произвольным классом?
посмотри литературу : парадигма "конверт-письмо", подсчет ссылок.
В общем, шаблоны тебе в руки - описать детально мне некогда...
В общем, шаблоны тебе в руки - описать детально мне некогда...
Можешь объяснить зачем тебе это нужно? В принципе проблем нет кто тебе мешает завести произвольный класс скажем :
class cTest
{
private:
int iTest;
public:
cTest(){};
};
int Function(cTest test)
{
}
Другой вопрос что подобное использование классов приводит к тому что ты не передаешь класс а создаешь его копию в стеке соответвенно это замедляет работу программы. Если тебя это не беспокоит то все что тебе нужно сделать чтобы подобный механизм работал безопасно заводи у класса для которого это нужно конструктор копировшик. Иначе будут проблеммы например такие:
class cTest
{
private:
void * m_pPointer;
public:
cTest(){ m_pPointer = new char[10000];}
virtual ~cTest() {delete []m_pPointer;}
}
int Function(cTest test)
{
}
void Funct()
{
cTest test;
Function(test);
}/// Вот здесь программа свалится с громкими матами.
Чтобы избежать этого делаешь так:
class cTest
{
private:
void * m_pPointer;
public:
cTest(){ m_pPointer = new char[10000];}
сTest(const cTest & test)
{
m_pPointer = new char[10000];
memcpy(m_pPointer, test.m_pPointer, 10000);
}
virtual ~cTest() {delete []m_pPointer;}
}
В этом случае вышеизложеный код ошибки не вызовет, и все же я рекомендую при передаче класса или структуры передавать ее как указатель или ссылку.
class cTest
{
private:
int iTest;
public:
cTest(){};
};
int Function(cTest test)
{
}
Другой вопрос что подобное использование классов приводит к тому что ты не передаешь класс а создаешь его копию в стеке соответвенно это замедляет работу программы. Если тебя это не беспокоит то все что тебе нужно сделать чтобы подобный механизм работал безопасно заводи у класса для которого это нужно конструктор копировшик. Иначе будут проблеммы например такие:
class cTest
{
private:
void * m_pPointer;
public:
cTest(){ m_pPointer = new char[10000];}
virtual ~cTest() {delete []m_pPointer;}
}
int Function(cTest test)
{
}
void Funct()
{
cTest test;
Function(test);
}/// Вот здесь программа свалится с громкими матами.
Чтобы избежать этого делаешь так:
class cTest
{
private:
void * m_pPointer;
public:
cTest(){ m_pPointer = new char[10000];}
сTest(const cTest & test)
{
m_pPointer = new char[10000];
memcpy(m_pPointer, test.m_pPointer, 10000);
}
virtual ~cTest() {delete []m_pPointer;}
}
В этом случае вышеизложеный код ошибки не вызовет, и все же я рекомендую при передаче класса или структуры передавать ее как указатель или ссылку.
Поручик Голицын
шатун сибирский обыкновенный
Передавать в функцию - это полбеды.
Нужно еще и возвращать в качестве результата работы функции.
Класс будет моделировать некую математическую сущность, и над его объектами нужно будет производить арифметические действия.
То есть главная собака зарыта в том, чтобы сделать что-то вроде такого:
class mTest{
public:
mTest operator+(mTest);
mTest operator*(mTest);
....
};
Со ссылками есть свой косяк: для того, чтобы передать в качестве результата mTest*, нужно его создать внутри функции. А отслживать все это дело трудновато будет, алгоритм уж больно навороченный (всякие рекурсии с ветвлениями).
2 Гость888:
можно чуть подробнее? что-то не могу нарыть ничего...
Хотя бы ссылку какую...
Нужно еще и возвращать в качестве результата работы функции.
Класс будет моделировать некую математическую сущность, и над его объектами нужно будет производить арифметические действия.
То есть главная собака зарыта в том, чтобы сделать что-то вроде такого:
class mTest{
public:
mTest operator+(mTest);
mTest operator*(mTest);
....
};
Со ссылками есть свой косяк: для того, чтобы передать в качестве результата mTest*, нужно его создать внутри функции. А отслживать все это дело трудновато будет, алгоритм уж больно навороченный (всякие рекурсии с ветвлениями).
2 Гость888:
можно чуть подробнее? что-то не могу нарыть ничего...
Хотя бы ссылку какую...
Поручик Голицын
шатун сибирский обыкновенный
Пока пришел к такому решению:
class mTest{
public:
mTest* operator+(mTest&);
mTest(const mTest*);
....
};
mTest* mTest::operator+(mTest& m){
mTest* temp = new mTest();
// .... addition
return temp;
}
mTest::mTest(const mTest* m){
// ... copying
delete m;
}
В этом случае операция
mTest m1, m2;
mTest m3 = m1 + m2;
нормально работает и память остается в целости.
Но все же мне это не очень нравится, т.к. если не сделать присваивание, то ненужный объект (сумма) не будет удален.
class mTest{
public:
mTest* operator+(mTest&);
mTest(const mTest*);
....
};
mTest* mTest::operator+(mTest& m){
mTest* temp = new mTest();
// .... addition
return temp;
}
mTest::mTest(const mTest* m){
// ... copying
delete m;
}
В этом случае операция
mTest m1, m2;
mTest m3 = m1 + m2;
нормально работает и память остается в целости.
Но все же мне это не очень нравится, т.к. если не сделать присваивание, то ненужный объект (сумма) не будет удален.
ASGS
guru
Если не очень лень, попробуй слазить вот сюда , там на Си-шном форуме народ тусуется подкованный. Глядишь, и расскажут, что почем.
правильно, что не нравится.
а что мешает сделать, как уже сказали? т.е. правильно задать конструктор
копирования и оператор присваивания. при этом тебе надо будет передавать
в функции только ссылки, а возвращать иногда придется и объекты (я что-то не
могу представить себе функцию, которой требовалось бы передавать именно
объект, а не ссылку, может, кто подскажет?)
пример:
class TEST{
private:
int a;
public:
TEST(void){ a = 0;}
TEST(int t){ a = t;}
TEST(const TEST& t){ a = t.a;}
~TEST(void){;}
TEST& operator=(const TEST& t){ a = t.a; return *this;}
TEST& operator+=(const TEST& t){ a += t.a; return *this;}
TEST operator+(const TEST& t) const { TEST tmp(*this); tmp += t; return tmp;}
};
т.е., у тебя есть конструктор копирования, и есть оператор присваивания.
в "+=" и "=" ты передаешь и возвращаешь ссылку на объект,
а в "+" передаешь ссылку, а возвращаешь объект (при этом неявно вызывается
конструктор копирования). можно, конечно, сделать и так:
TEST& operator+(const TEST &t){ return *this += t;}
при этом не будет "лишнего" вызова конструктора, но появится побочный
эффект: в вызове "+" будет изменятся первый аргумент:
TEST t1, t2, t3;
t3 = t1 + t2; // изменится t1.
а что мешает сделать, как уже сказали? т.е. правильно задать конструктор
копирования и оператор присваивания. при этом тебе надо будет передавать
в функции только ссылки, а возвращать иногда придется и объекты (я что-то не
могу представить себе функцию, которой требовалось бы передавать именно
объект, а не ссылку, может, кто подскажет?)
пример:
class TEST{
private:
int a;
public:
TEST(void){ a = 0;}
TEST(int t){ a = t;}
TEST(const TEST& t){ a = t.a;}
~TEST(void){;}
TEST& operator=(const TEST& t){ a = t.a; return *this;}
TEST& operator+=(const TEST& t){ a += t.a; return *this;}
TEST operator+(const TEST& t) const { TEST tmp(*this); tmp += t; return tmp;}
};
т.е., у тебя есть конструктор копирования, и есть оператор присваивания.
в "+=" и "=" ты передаешь и возвращаешь ссылку на объект,
а в "+" передаешь ссылку, а возвращаешь объект (при этом неявно вызывается
конструктор копирования). можно, конечно, сделать и так:
TEST& operator+(const TEST &t){ return *this += t;}
при этом не будет "лишнего" вызова конструктора, но появится побочный
эффект: в вызове "+" будет изменятся первый аргумент:
TEST t1, t2, t3;
t3 = t1 + t2; // изменится t1.
Сейчас читают
Сладкий поцелуй
29270
139
Бедные и гордые
23687
183
"Телячьи нежности". Кто за?
10895
101
Поручик Голицын
шатун сибирский обыкновенный
Уже все разрулил на rsdn (ASGS, thnx за ссылку ). Причем там просто помогли вспомнить то, что я и так знал :).
И ну их на фиг, побочные эффекты... :). Тогда теряется смысл операции +, можно обойтись одним +=.
Лучше сделать коротко и просто:
TEST operator+(const TEST& t) const { return TEST(a + t.a);}
И ну их на фиг, побочные эффекты... :). Тогда теряется смысл операции +, можно обойтись одним +=.
Лучше сделать коротко и просто:
TEST operator+(const TEST& t) const { return TEST(a + t.a);}