Попробуйте это, это должно быть работа, иначе вам нужно распечатать ошибку, чтобы указать вашу проблему
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * from Users WHERE UserName LIKE '$username'";
$result = mysql_query($sql,$con);
while($row = mysql_fetch_array($result))
{
echo $row['FirstName'];
}
Существует много статей, объясняющих, почему вы никогда не должны вызывать виртуальные функции в конструкторе и деструкторе на C ++. Посмотрите здесь здесь и здесь , чтобы узнать, что происходит за сценой во время таких вызовов.
Короче говоря, объекты строятся от базы до получен. Поэтому, когда вы пытаетесь вызвать виртуальную функцию из конструктора базового класса, переопределение из производных классов еще не произошло, поскольку производные конструкторы еще не были вызваны.
Если PrintStartMessage () не была чистой виртуальной функцией, а обычной виртуальной функцией, компилятор не стал бы жаловаться на нее. Однако вам все равно придется выяснить, почему производная версия PrintStartMessage () не вызывается.
Поскольку производный класс вызывает конструктор базового класса перед его собственным конструктором, производный класс ведет себя как базовый класс и поэтому вызывает функцию базового класса.
Вы не должны вызывать функцию virtual
в конструкторе. Период . Вам нужно найти некоторое обходное решение, например сделать PrintStartMessage
не virtual
и явно поставить вызов в каждом конструкторе.
Ближе всего вы можете сделать что-то подобное, чтобы полностью построить свой объект, а затем вызвать метод после:
template <typename T>
T construct_and_print()
{
T obj;
obj.PrintStartMessage();
return obj;
}
int main()
{
Derived derived = construct_and_print<Derived>();
}
Пытаться вызывать чистый абстрактный метод из производного, пока этот объект все еще строится, является небезопасным. Это похоже на попытку заполнить газ в автомобиле, но этот автомобиль все еще находится на сборочной линии, и газовый баллон еще не установлен. Я имею в виду, какого черта вы ожидаете?
Вы не можете сделать это так, как вы себе представляете, потому что вы не можете вызывать производные виртуальные функции внутри конструктора базового класса - объект еще не имеет производного типа. Но вам это не нужно.
Предположим, что вы хотите сделать что-то вроде этого:
class MyBase {
public:
virtual void PrintStartMessage() = 0;
MyBase() {
printf("Doing MyBase initialization...\n");
PrintStartMessage(); // ⚠ UB: pure virtual function call ⚠
}
};
class Derived : public MyBase {
public:
virtual void PrintStartMessage() { printf("Starting Derived!!!\n"); }
};
Желаемая трассировка выполнения:
Doing MyBase initialization...
Starting Derived!!!
Но для этого нужны конструкторы! Просто отбросьте виртуальную функцию и сделайте конструктор производного для выполнения задания!
class MyBase {
public:
MyBase() { printf("Doing MyBase initialization...\n"); }
};
class Derived : public MyBase {
public:
Derived() { printf("Starting Derived!!!\n"); }
};
Результат, ну, что мы ожидаем:
Doing MyBase initialization...
Starting Derived!!!
Это doesn 't принудительно использовать производные классы, чтобы явно реализовать функциональность PrintStartMessage
, хотя. Но, с другой стороны, подумайте дважды, действительно ли это необходимо, поскольку они в любом случае всегда могут обеспечить пустую реализацию.
Как было сказано выше, if вы должны называть PrintStartMessage
до того, как Derived
был конструктором, вы не можете этого сделать, потому что еще нет объекта Derived
для вызова PrintStartMessage
. Было бы бессмысленно требовать, чтобы PrintStartMessage
был нестационарным членом, потому что он не имел бы доступа ни к одному из членов данных Derived
.
В качестве альтернативы мы можем сделать его статическим членом следующим образом:
class MyBase {
public:
MyBase() {
printf("Doing MyBase initialization...\n");
}
};
class Derived : public MyBase {
public:
static void PrintStartMessage() { printf("Derived specific message.\n"); }
};
Возникает естественный вопрос о том, как он будет называться?
Есть два решения, которые я вижу: один из них похож на @greatwolf, где вы должны называть его вручную. Но теперь, поскольку это статический член, вы можете вызвать его до того, как был сконструирован экземпляр MyBase
:
template<class T>
T print_and_construct() {
T::PrintStartMessage();
return T();
}
int main() {
Derived derived = print_and_construct<Derived>();
}
Выход будет
Derived specific message.
Doing MyBase initialization...
подход заставляет все производные классы реализовать PrintStartMessage
. К сожалению, это справедливо только тогда, когда мы строим их с нашей фабричной функцией ..., что является огромным недостатком этого решения.
Второе решение - прибегнуть к любопытно повторяющейся шаблонной схеме (CRTP). Сообщая MyBase
полный тип объекта во время компиляции, он может выполнить вызов внутри конструктора:
template<class T>
class MyBase {
public:
MyBase() {
T::PrintStartMessage();
printf("Doing MyBase initialization...\n");
}
};
class Derived : public MyBase<Derived> {
public:
static void PrintStartMessage() { printf("Derived specific message.\n"); }
};
Выходной сигнал будет таким, как ожидалось, без необходимости использования специализированной заводской функции.
Когда выполняется MyBase
, его уже ОК, чтобы получить доступ к своим членам. Мы можем сделать PrintStartMessage
доступ к вызываемому MyBase
, который его назвал:
template<class T>
class MyBase {
public:
MyBase() {
T::PrintStartMessage(this);
printf("Doing MyBase initialization...\n");
}
};
class Derived : public MyBase<Derived> {
public:
static void PrintStartMessage(MyBase<Derived> *p) {
// We can access p here
printf("Derived specific message.\n");
}
};
Следующие действия также действительны и очень часто используются, хотя и немного опасны:
template<class T>
class MyBase {
public:
MyBase() {
static_cast<T*>(this)->PrintStartMessage();
printf("Doing MyBase initialization...\n");
}
};
class Derived : public MyBase<Derived> {
public:
void PrintStartMessage() {
// We can access *this member functions here, but only those from MyBase
// or those of Derived who follow this same restriction. I.e. no
// Derived data members access as they have not yet been constructed.
printf("Derived specific message.\n");
}
};
] Еще один вариант - немного изменить код. IMO это действительно предпочтительное решение, если вам абсолютно необходимо вызвать переопределенное PrintStartMessage
изнутри MyBase
.
Это предложение состоит в том, чтобы отделить Derived
от MyBase
следующим образом:
class ICanPrintStartMessage {
public:
virtual ~ICanPrintStartMessage() {}
virtual void PrintStartMessage() = 0;
};
class MyBase {
public:
MyBase(ICanPrintStartMessage *p) : _p(p) {
_p->PrintStartMessage();
printf("Doing MyBase initialization...\n");
}
ICanPrintStartMessage *_p;
};
class Derived : public ICanPrintStartMessage {
public:
virtual void PrintStartMessage() { printf("Starting Derived!!!\n"); }
};
Вы инициализируете MyBase
следующим образом:
int main() {
Derived d;
MyBase b(&d);
}