Класс не инициализируется
В файлах Hash.h и Hash.cpp описан шаблон класса CHashTable.
В файле People.h структура CPeopCust.
Проблема следующего содежания: хочу объявить перерменную
типа CHashTable в диалоговом окне (классе диалогового окна)
BankDlg.h:
#pragma once
#include "afxwin.h"
#include "Hash.h"
...
// CBankDlg dialog
class CBankDlg : public CDialog
{
...
public:
...
CHashTable<T> IndexPeop();
...
};
Все вроде ОК...
// BankDlg.cpp : implementation file
#include "stdafx.h"
#include "Bank.h"
#include "BankDlg.h"
#include "People.h"
BOOL CBankDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...инициализирую переменную...
CHashTable<CPeopCust> IndexPeop();
...
}
...
...и тут происходит самое интересное. Компилятор не дает никаких ошибок,
но есть предупреждение:
Compiling...
BankDlg.cpp
c:\Мои документы\Visual Studio Projects\Bank\BankDlg.cpp(107) : warning C4930: 'CHashTable<T> IndexPeop(void)': prototyped function not called (was a variable definition intended?)
with
[
T=CPeopCust
]
Linking...
т.е. конструктор класса не выполнился, соответственно класс не инициализирован.
Вопрос вытекает сам собой, в чем дело?
public:
...
CHashTable<T> IndexPeop();
Это объявление метода-члена, а не переменной-члена. Правильно будет так:
public:
CHashTable<T> IndexPeop;
BOOL CBankDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...инициализирую переменную...
CHashTable<CPeopCust> IndexPeop();
...
}
Здесь не инициализация переменной, объявленной в классе, а создание новой локальной переменной.
Конструктор для переменной, объявленной в классе, можно вызвать лишь в конструкторе класса:
CBankDlg::CBankDlg() : IndexPeop()
{
}
Если это не устраивает, объяви в классе CBankDlg указатель на тип CHashTable<T> и создавай объект динамически, где это нужно.
// CBankDlg dialog
class CBankDlg : public CDialog
{
public:
CHashTable<T> *pIndexPeop;
};
BOOL CBankDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...инициализирую переменную...
pIndexPeop = new CHashTable<CPeopCust>();
...
}
Если это не устраивает, объяви в классе CBankDlg указатель на тип CHashTable<T> и создавай объект динамически, где это нужно.
// CBankDlg dialog
class CBankDlg : public CDialog
{
public:
CHashTable<T> *pIndexPeop;
};
BOOL CBankDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...инициализирую переменную...
pIndexPeop = new CHashTable<CPeopCust>();
...
}
Так и сделал, но лучше не стало:
c:\Мои документы\Visual Studio Projects\Bank\BankDlg.cpp(171) : error C2440: '=' : cannot convert from 'CHashTable<T> *' to 'CHashTable<T> *'
with
[
T=CPeopCust
]
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
// CBankDlg dialog
class CBankDlg : public CDialog
{
public:
CHashTable<CPeopCust> *pIndexPeop;
};
BOOL CBankDlg::OnInitDialog()
{
CDialog::OnInitDialog();
...инициализирую переменную...
pIndexPeop = new CHashTable<CPeopCust>();
...
}
Очепяточка!
// CBankDlg dialog
class CBankDlg : public CDialog
{
public:
CHashTable<CPeopCust> *pIndexPeop;
};
:) Спасибо! Вроде прокатило!
Нифига оказывается не работает. Компилятор во че выдает:
BankDlg.cpp
Linking...
BankDlg.obj : error LNK2019: unresolved external symbol "public: __thiscall CHashTable<struct CPeopCust>::CHashTable<struct CPeopCust>(int)" (??0?$CHashTable@UCPeopCust@@@@QAE@H@Z) referenced in function "protected: virtual int __thiscall CBankDlg::OnInitDialog(void)" (?OnInitDialog@CBankDlg@@MAEHXZ)
Debug/Bank.exe : fatal error LNK1120: 1 unresolved externals
Build log was saved at "file://c:\Мои документы\Visual Studio Projects\Bank\Debug\BuildLog.htm"
Bank - 2 error(s), 0 warning(s)
:( Поторопился я!!!
Нифига оказывается не работает. Компилятор во че выдает:
BankDlg.cpp
Linking...
BankDlg.obj : error LNK2019: unresolved external symbol "public: __thiscall CHashTable<struct CPeopCust>::CHashTable<struct CPeopCust>(int)" (??0?$CHashTable@UCPeopCust@@@@QAE@H@Z) referenced in function "protected: virtual int __thiscall CBankDlg::OnInitDialog(void)" (?OnInitDialog@CBankDlg@@MAEHXZ)
Debug/Bank.exe : fatal error LNK1120: 1 unresolved externals
Build log was saved at "file://c:\Мои документы\Visual Studio Projects\Bank\Debug\BuildLog.htm"
Bank - 2 error(s), 0 warning(s)
Ошибка заключается в том, что ты вызываешь в CBankDlg::OnInitDialog() конструктор
CHashTable<struct CPeopCust>::CHashTable<struct CPeopCust>(int)
т.е. видимо ты написал
pIndexPeop = new CHashTable<CPeopCust>(какое-то числовое значение);
Вместо
pIndexPeop = new CHashTable<CPeopCust>();
Кстати, можно просто написать:
pIndexPeop = new CHashTable<CPeopCust>;
т.е. видимо ты написал
pIndexPeop = new CHashTable<CPeopCust>(какое-то числовое значение);
Да так и сделал ...
Вместо
pIndexPeop = new CHashTable<CPeopCust>();
Кстати, можно просто написать:
pIndexPeop = new CHashTable<CPeopCust>;
Пробовал pIndexPeop = new CHashTable<CPeopCust>() и pIndexPeop = new CHashTable<CPeopCust>, одна и та же ошибка:
BankDlg.cpp
c:\Мои документы\Visual Studio Projects\Bank\BankDlg.cpp(173) : error C2512: 'CHashTable<T>' : no appropriate default constructor available
with
[
T=CPeopCust
]
Может посмотришь исходники, я уже 2-ую неделю борюсь с этим?
Да так и сделал ...
Пробовал pIndexPeop = new CHashTable<CPeopCust>() и pIndexPeop = new CHashTable<CPeopCust>, одна и та же ошибка:
BankDlg.cpp
c:\Мои документы\Visual Studio Projects\Bank\BankDlg.cpp(173) : error C2512: 'CHashTable<T>' : no appropriate default constructor available
with
[
T=CPeopCust
]
Может посмотришь исходники, я уже 2-ую неделю борюсь с этим?
Архив поврежден, видимо, при перекачке. Но из того, что смог открыть, видно, что в Hash.h объявлен конструктор
template<class T>
CHashTable::CHashTable(int nbuckets);
сл-но надо все же ври вызове передовать численное значение.
В Hash.cpp реализация
template<class T>
CHashTable<T>::CHashTable(int nbuckets)
Но шаблонный класс называется то
template<class T> CHashTable,
а не
template<class T> CHashTable<T>
Короче говоря, в Hash.cpp надо написать
template<class T>
CHashTable::CHashTable(int nbuckets)
вместо
template<class T>
CHashTable<T>::CHashTable(int nbuckets)
Кстати в HashTable.h объявлен шаблонный класс template <class T>
class HashTable<T>
Может возникнуть путанница.
Но шаблонный класс называется то
template<class T> CHashTable,
а не
template<class T> CHashTable<T>
Короче говоря, в Hash.cpp надо написать
template<class T>
CHashTable::CHashTable(int nbuckets)
вместо
template<class T>
CHashTable<T>::CHashTable(int nbuckets)
В том то все и дело, что так:
template<class T>
CHashTable::CHashTable(int nbuckets)
не работает, компилятор говорит, что шаблону нужно указывать в качестве параметра "шаблонный параметр" (небольшой каламбур), ну в общем надо делать так: template<class T>
CHashTable<T>::CHashTable(int nbuckets)
Но и так ничего не работает.
Может если есть время и возможность я скину исходник на мыло, посмотришь, может какие идеи появятся?
В том то все и дело, что так:
template<class T>
CHashTable::CHashTable(int nbuckets)
не работает, компилятор говорит, что шаблону нужно указывать в качестве параметра "шаблонный параметр" (небольшой каламбур), ну в общем надо делать так: template<class T>
CHashTable<T>::CHashTable(int nbuckets)
Но и так ничего не работает.
Может если есть время и возможность я скину исходник на мыло, посмотришь, может какие идеи появятся?
Блин... Вот мы тормозим. Всё элементарно, Ватсон!
Дело в том, что шаблонный класс не может быть скомпилирован без инстанирования определенным типом. Т.о. при компиляции Hash.cpp не создается соотв. объектного кода, взгляни на Hash.obj, там полный бред. Тоже самое, кстати, и с LinkedList.cpp
Решение: перенести всё из Hash.cpp в Hash.h
Этим, кстати, объясняется, что весь atl/wtl находиться в *.h
И ещё я рекомендую вог все *.h вставлять CodeGuard-ы, т.е. запись в самом начале и в самом конце заголовочного файла, исключающее его повторное включение:
#ifndef _HASH_H_ // В начале файла
#define _HASH_H_ // _HASH_H_ - уникальный макрос
.................
#endif //_HASH_H_ // В конце файла
Имя уникального макроса лично я определяю по названию файла.
Можно конечно воспользоваться #pragma once, но мне как-то не по душе эта M$-фича.
Действительно, правильно писать
template<class T>
CHashTable<T>::CHashTable(int nbuckets)
Незабудь, что в BOOL CBankDlg::OnInitDialog() нужно вызвать конструктор с целочисленным аргументом:
pIndexPeop=new CHashTable<CPeopCust>(777);
---------------------------
P.S. Все гениальное просто!