У меня есть следующая программа, в которой я пытаюсь использовать указатель функции для «сохранения памяти», сохраняя адрес функции в переменной-члене, которая является указателем функции.
Указатель функции — это provideService_proxy
, который определяется typedef void (* provideService_proxy )(std::string product)
.
Я пытаюсь создать экземпляр RealShop realShop_, а затем вызываю RealShop::provideService(string product)
. Кроме того, я хочу сохранить адрес provideService
.
Однако я сталкиваюсь с ошибкой. Не могли бы вы помочь?
#include "iostream"
#include "string"
using namespace std;
// needed preprocessor to prevend loop include
#ifndef ISHOP
#define ISHOP
#include "string"
class IShop{
public:
IShop(){};
virtual void provideService(std::string product) = 0;
virtual ~IShop(){};
};
#endif
class RealShop: public IShop {
public:
RealShop(){};
virtual ~RealShop(){};
virtual void provideService(std::string product) override{
cout<<" shop is building "<<product<<" in warehouse"<<endl;
if (specialOrder_ == true){
specialService("Minh");
}
collectMaterial();
} ;
private:
static const bool specialOrder_ = true;
void collectMaterial(){
cout<<" collect material to build product"<<endl;
};
void specialService(std::string customerName){
std::cout<<"provide custom order to customer "<<customerName<<std::endl;
customerName_ = customerName;
}; // newly added
std::string customerName_;
};
class ShopProxy : public IShop {
public:
ShopProxy(){};
virtual ~ShopProxy(){};
virtual void provideService(std::string product) override {
if ( realShop_ == nullptr ) {
std::cout<<"Proxy creates RealShop on request"<<std::endl;
// realShop_ = new RealShop(); //create RealShop, call RealShop to do service
// provideService_proxy = reinterpret_cast<provideService_proxy>(&RealShop::provideService);
provideService_proxy = init_RealService (product);
}
else{
std::cout<<"Proxy can provide service"<<std::endl;
// RealShop is available in Proxy's memory.
// don't have to reload, just run logic
// realShop_ ->provideService(product);
provideService_proxy (product);
}
};
private:
typedef void (* provideService_proxy )(std::string product);
provideService_proxy init_RealService ( std::string product ){
realShop_ = new RealShop();
return reinterpret_cast<provideService_proxy>(&RealShop::provideService);
};
RealShop * realShop_ = nullptr; // safe initialization of pointer
};
int main()
{
std::string requestProduct1 = "a doll";
IShop * myShopProxy = new ShopProxy();
// myShopProxy creates RealShop
myShopProxy->provideService(requestProduct1);
// myShopProxy already has RealShop, and can provide service.
std::string requestProduct2 = "a toy";
myShopProxy->provideService(requestProduct1);
// delete myShopProxy will delete RealShop and data saved in memory
delete myShopProxy;
// create new proxy
IShop * myShopProxy2 = new ShopProxy();
// myShopProxy has to create new RealShop again and reload data.
myShopProxy2->provideService(requestProduct1);
delete myShopProxy2;
}
Ошибка:
error: expected unqualified-id before '=' token
50 | provideService_proxy = init_RealService (product);
«Я пытаюсь использовать указатель функции для «сохранения памяти», сохраняя адрес функции в переменной-члене»: не уверен, как это должно работать. Хранение указателя на функцию увеличивает использование памяти, поскольку значение указателя необходимо где-то хранить.
Кроме того, указатели функций и указатели функций-членов — это не одно и то же. Вы не можете хранить указатель на (нестатическую) функцию-член в указателе функции. reinterpret_cast
не должно работать.
если я просто реализую realShop_->provideService(product)
, когда я вызываю вызов функции ShopProxy::provideService
во второй раз, realShop->provideService(product)
будет вызываться снова. Это требует добавления в стек вызовов дополнительной информации для вызова функции и потери памяти. Таким образом, я хочу сохранить адрес realShop_->provideService(product)
в переменной-члене. Вы правы, указывая на мои ошибки. Но у меня все еще есть вопрос. Можно ли сохранить адрес функции в указатель члена?
Это объявление typedef
typedef void (* provideService_proxy )(std::string product);
объявляет имя provideService_proxy
как псевдоним для типа void ( * )( std::string )
. Он не объявляет никаких объектов типа указателя.
Таким образом, используя это имя typedef в качестве объекта в операторе выражения
provideService_proxy = init_RealService (product);
выдает ошибку.
Обратите внимание, что вам нужно объявить указатель на функцию-член, а не на отдельную функцию.
Я понимаю. Я запутался между типом данных provideService_proxy
и переменной-членом, которая имеет тип данных как provideService_proxy
.
после того, как я правильно определил тип данных и указатель на функцию-член. Я мог скомпилировать программу, но все еще имел ошибку seg fault. По сути, я удаляю typedef и использую void (* provideService_proxy )(std::string product)
в качестве указателя на функцию. Я хотел бы реализовать функцию init_RealService, чтобы она сохраняла адрес realShop_->provideService(product)
в указатель на функцию-член. Не могли бы вы предложить мне?
@MinhPham Это выражение realShop_->provideService(product) является вызовом функции. Вам нужно объявить указатель на функцию-член и присвоить ему имя функции.
это указатель на функцию-член, которую вы имеете в виду? (realShop_->*provideService_proxy)(product)
?
@MinhPham Чтобы объявить указатель на функцию-член, вам нужно написать, например, void ( RealShop::*pf )( std::string );
В моей программе есть несколько ошибок:
Во-первых, я запутался и забыл объявить указатель на функцию-член:
void (* provideService_proxy )(std::string product) = nullptr;
Вместо этого у меня был только тип данных указателя функции по этой строке:
typedef void (* provideService_proxy )(std::string product)
Во-вторых, чтобы присвоить адрес RealShop::provideService(string)
указателю на функцию, мне нужен более простой и явно определенный указатель на функцию как:
void (RealShop::* provideService_proxy )(std::string) = nullptr ;
Чтобы сохранить адрес RealShop::provideService(string)
, я должен сделать следующее:
realShop_ = new RealShop();
provideService_proxy = &RealShop::provideService;
(realShop_->*provideService_proxy)(product);
Чтобы вызвать RealShop::provideService(string)
через указатель функции, мне нужно сделать:
(realShop_->*provideService_proxy)(product);
Это моя последняя программа:
#include "iostream"
#include "string"
using namespace std;
// needed preprocessor to prevend loop include
#ifndef ISHOP
#define ISHOP
#include "string"
class IShop{
public:
IShop(){};
virtual void provideService(std::string product) = 0;
virtual ~IShop(){};
};
#endif
class RealShop: public IShop {
public:
RealShop(){
cout<<"RealShop constructor"<<endl;
};
virtual ~RealShop(){
cout<<"RealShop destructor"<<endl;
};
virtual void provideService(std::string product) override{
cout<<" shop is building "<<product<<endl;
} ;
};
class ShopProxy : public IShop {
public:
ShopProxy(){
cout<<"**ShopProxy constructor**"<<endl;
};
virtual ~ShopProxy(){
cout<<"**ShopProxy destructor**"<<endl;
delete realShop_;
};
virtual void provideService(std::string product) override {
if ( realShop_ == nullptr ) {
//create RealShop, call RealShop to do service
// provideService_proxy = (void (*)(std::string))init_RealService (product);
init_RealService (product);
}
else{
std::cout<<"Proxy can provide service"<<std::endl;
// RealShop is available in Proxy's memory.
// don't have to request another function call, and add to stack
// save stack memory by using function pointer.
(realShop_->*provideService_proxy)(product);
}
};
private:
// typedef void (* functPtr )(std::string product);
// void (* provideService_proxy )(std::string product) = nullptr;
void (RealShop::* provideService_proxy )(std::string) = nullptr ;
void init_RealService ( std::string product ){
std::cout<<"Proxy creates RealShop on request"<<std::endl;
realShop_ = new RealShop();
std::cout<<"init_RealService saves realShop_->provideService to function pointer"<<endl;
provideService_proxy = &RealShop::provideService;
(realShop_->*provideService_proxy)(product);
};
RealShop * realShop_ = nullptr; // safe initialization of pointer
};
int main()
{
std::string requestProduct1 = "REQUEST 1: a doll";
IShop * myShopProxy = new ShopProxy();
// myShopProxy creates RealShop
myShopProxy->provideService(requestProduct1);
// myShopProxy already has RealShop, and can provide service.
std::string requestProduct2 = "REQUEST 2: a toy";
myShopProxy->provideService(requestProduct2);
// delete myShopProxy will delete RealShop and data saved in memory
delete myShopProxy;
// create new proxy
std::string requestProduct3 = "REQUEST 3: a fan";
IShop * myShopProxy2 = new ShopProxy();
// myShopProxy has to create new RealShop again and reload data.
myShopProxy2->provideService(requestProduct3);
delete myShopProxy2;
}
Спасибо @Vlad From Moscow за помощь!
Вы объявили
provideService_proxy
типом, а не элементом данных. Вы не можете назначать типы. Удалитеtypedef
, если вы хотите, чтобы он был элементом данных.