Код: Выделить всё
Account
цель состоит в том, чтобы использовать разные Logger: один для фундаментальных типов, таких как long, и другой, адаптированный для объектов Account, причем последний принимает аргумент-указатель из-за полиморфизма Account .
Полагаю, этого можно было бы достичь полностью с помощью шаблонов, однако решение этой проблемы должно пролить некоторый свет на то, как специализация шаблонов работает для иерархий наследования классов, если вообще работает.
Приведенный ниже MWE не компилируется успешно, см. ссылку на компилятор.
Код: Выделить всё
#include
//#include
//#include
class Account {
public:
virtual ~Account() {}
virtual const long getId() = 0;
};
class CheckingAccount: public Account {
public:
CheckingAccount() = default;
CheckingAccount(const long id): _id{id} {}
~CheckingAccount() {}
const long getId() {
return _id;
}
private:
long _id;
};
////////////////////////////////////////////////////////////////
template class Logger {
public:
virtual void logTransfer(T, T, const double) = 0;
};
template class ConsoleLogger : public Logger {
public:
void logTransfer(T from, T to, const double amount) override {
printf("[console] %ld -> %ld: %f\n", from, to, amount);
}
};
// template class specialization
template class ConsoleLogger : public Logger {
public:
void logTransfer(Account* from, Account* to, const double amount) override {
printf("[console] %ld -> %ld: %f\n", from->getId(), to->getId(), amount);
}
};
////////////////////////////////////////////////////////////////////
template struct Bank {
void setLogger(Logger* new_logger) {
logger = new_logger;
}
void logTransfer(T from, T to, const double amount) {
if(logger)
logger->logTransfer(from, to, amount);
}
private:
Logger* logger;
};
// template class specialization
template struct Bank {
void setLogger(Logger* new_logger) {
logger = new_logger;
}
void logTransfer(Account* from, Account* to, const double amount) {
if(logger)
logger->logTransfer(from, to, amount);
}
private:
Logger* logger;
};
/////////////////////////////////////////////
int main() {
// try with long input
ConsoleLogger console_logger;
Bank bank;
bank.setLogger(&console_logger);
bank.logTransfer(500L, 1000L, 23.56);
// try with Account input
CheckingAccount* a = new CheckingAccount{500};
CheckingAccount* b = new CheckingAccount{1000};
printf("Account no.%ld\n", a->getId());
printf("Account no.%ld\n", b->getId());
ConsoleLogger console_logger2;
Bank bank2;
bank2.setLogger(&console_logger2);
bank2.logTransfer(a, b, 42.81);
delete a;
delete b;
}
Код: Выделить всё
main.cpp: In function ‘int main()’:
main.cpp:94:19: error: cannot convert ‘ConsoleLogger*’ to ‘Logger*’
94 | bank2.setLogger(&console_logger2);
| ^~~~~~~~~~~~~~~~
| |
| ConsoleLogger*
main.cpp:65:36: note: initializing argument 1 of ‘void Bank::setLogger(Logger*)’
65 | void setLogger(Logger* new_logger) {
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~
main.cpp: In instantiation of ‘void ConsoleLogger::logTransfer(T, T, double) [with T = CheckingAccount*]’:
main.cpp:35:8: required from here
main.cpp:36:27: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘CheckingAccount*’ [-Wformat=]
36 | printf("[console] %ld -> %ld: %f\n", from, to, amount);
| ~~^ ~~~~
| | |
| long int CheckingAccount*
Я пытался специализировать Logger непосредственно из Logger и получить от него ConsoleLogger, но получил то же сообщение об ошибке от компилятора.
Подробнее здесь: https://stackoverflow.com/questions/793 ... te-classes