C++ 三重继承,没有唯一的最终重写器
我有一个名为Request的模板基类:C++ 三重继承,没有唯一的最终重写器,c++,inheritance,C++,Inheritance,我有一个名为Request的模板基类: template <typename Input, typename Output> class Request { public: // Constructor Request(const std::string& request) : request_(request) {} // Operation virtual Output select(const Input&
template <typename Input, typename Output>
class Request
{
public:
// Constructor
Request(const std::string& request) : request_(request) {}
// Operation
virtual Output select(const Input& arg) = 0;
protected:
// Attribute
const std::string request_;
};
然后,为了测试我的代码,我创建了一个通用的伪类:
template <typename Input, typename Output>
class Fake : public virtual Request<Input, Output>
{
public:
// Constructor
Fake(const std::string& request) : Request<Input, Output>(request) {}
// Fake Operation
virtual Output select(const Input& arg)
{
return data_[arg];
}
// Add fake data
void add_data(const Input& key, const Output& data)
{
data_[key] = data;
}
private:
// Contains fake data
std::map<Input, Output> data_;
};
但是,g++未能抱怨:
“输出请求::选择(常量输入&)[输入=标准::基本字符串;
“FakePhoneRequest”类中的Output=std::basic_string]'
FakePhoneRequest:public NationalPhoneRequest,public
国际电话请求,公开伪造
我有几个问题。
1) 为什么会失败?
2) 我脑子里有一个触发器告诉我我做错了什么,可能是使用了三重继承
我做得对吗?您的子类实际上继承了三个完全独立的“select”函数,它们仍然存在于子类中,“using”只允许您使用“select”作为其中一个函数的简写名称。这样做不会“组合”现有的三个select函数 基本上,继承三个同名的虚拟函数会给子函数三个不同的虚拟函数指针,每个select的“类型”对应一个指针(因为它们在不同的继承者体系结构中) C++不允许这样做,因为无法正确地分别定义所有三个select函数的子版本,因为它们都必须被称为“select”,这会让编译器非常困惑 如果三个select函数采用不同的参数,则可能不会出现问题。函数的“内部”名称由给定名称和一些定义其参数的标记来定义。因此,接受一个字符串的“select”是另一个接受两个字符串的“named”函数。只要编译器能够计算出哪个函数是哪个函数,那么重用名称就没有问题 话虽如此,代码还是有点臭味。任何时候,当你对与继承相关的事情变得太深刻时,几乎总会有更好的方法来做事情。一个经验法则是尝试保持继承只有1级深度,并且基类是抽象的(即不能自己实例化)。然后使用指向基类的指针将功能“插入”到不同的类中(这些类本身可能是1-deep抽象类的子类)
e、 g.创建一个“PhoneDialler”类,该类具有指向PhoneRequest的指针。然后有一个函数返回一个指向PhoneRequest类型之一的指针。这称为工厂方法。PhoneDialler然后只请求一个PhoneRequest对象并使用它,根本不需要知道PhoneRequest的子类。这使得系统更容易用新类型进行扩展。您的子类实际上继承了三个完全独立的“select”函数,这些函数仍然存在于子类中,“using”只允许您使用“select”作为其中一个函数的简写名。这样做不会“组合”现有的三个select函数 基本上,继承三个同名的虚拟函数会给子函数三个不同的虚拟函数指针,每个select的“类型”对应一个指针(因为它们在不同的继承者体系结构中) C++不允许这样做,因为无法正确地分别定义所有三个select函数的子版本,因为它们都必须被称为“select”,这会让编译器非常困惑 如果三个select函数采用不同的参数,则可能不会出现问题。函数的“内部”名称由给定名称和一些定义其参数的标记来定义。因此,接受一个字符串的“select”是另一个接受两个字符串的“named”函数。只要编译器能够计算出哪个函数是哪个函数,那么重用名称就没有问题 话虽如此,代码还是有点臭味。任何时候,当你对与继承相关的事情变得太深刻时,几乎总会有更好的方法来做事情。一个经验法则是尝试保持继承只有1级深度,并且基类是抽象的(即不能自己实例化)。然后使用指向基类的指针将功能“插入”到不同的类中(这些类本身可能是1-deep抽象类的子类)
e、 g.创建一个“PhoneDialler”类,该类具有指向PhoneRequest的指针。然后有一个函数返回一个指向PhoneRequest类型之一的指针。这称为工厂方法。PhoneDialler然后只请求一个PhoneRequest对象并使用它,根本不需要知道PhoneRequest的子类。这使得系统更容易用新类型进行扩展。非常感谢,但是,我担心它会允许您将InternationalPhoneRequest放入一个应包含国家变量的变量中。如果我想在InterNationalPhoneRequest中添加特殊操作,而你的工厂函数处理向你的请求对象发出指针,因此它包含关于哪种类型合适的规则,那该怎么办?我不明白。我需要NationalPhoneRequest和InterNationalPhoneRequest从PhoneRequest派生出来,PhoneRequest本身就是从请求派生出来的。我的FakePhoneRequest必须至少是一个PhoneRequest(以便Foo可以使用它)和一个Fake(以便我可以添加我的特殊数据)。为了进行更严格的输入,我选择了FakePhoneRequest必须继承InternationalPhoneRequest和NationalPhoneRequest,因为我希望不可能将InternationalPhoneRequest放入设计用于包含NationalPhoneRequest的var中。我应该如何使用工厂模式来设计它?尝试导出单独的FakeNationalPhoneRequest和FakeInternationalPhoneRequest。使它们从各自的类和“Fake”继承,但阻止Fake也从请求继承。让派生类处理“fakeness”。使用工厂模式,您可以在其他对象请求项的地方创建一个类或函数,工厂确保它们
class NationalPhoneRequest : public virtual PhoneRequest
{
public:
// Real request that actually get data from the database
virtual std::string select(const std::string& username)
{
username_ = username;
return call_sql_national(request_, username_);
}
};
class InterNationalPhoneRequest : public virtual PhoneRequest
{
public:
// Real request that actually get data from the database
virtual std::string select(const std::string& username)
{
username_ = username;
return call_sql_international(request_, username_);
}
};
template <typename Input, typename Output>
class Fake : public virtual Request<Input, Output>
{
public:
// Constructor
Fake(const std::string& request) : Request<Input, Output>(request) {}
// Fake Operation
virtual Output select(const Input& arg)
{
return data_[arg];
}
// Add fake data
void add_data(const Input& key, const Output& data)
{
data_[key] = data;
}
private:
// Contains fake data
std::map<Input, Output> data_;
};
class FakePhoneRequest : public NationalPhoneRequest, public InterNationalPhoneRequest, public Fake<std::string, std::string>
{
public:
using Fake<std::string, std::string>::select;
};
class Foo
{
public:
Foo(NationalPhoneRequest* nat, InterNationalPhoneRequest* internat)
: nat_(nat)
, internat_(internat)
{
}
std::string getNatPhoneNumber(const std::string& user)
{
return nat_->select(user);
}
std::string getInterPhoneNumber(const std::string& user)
{
return internat_->select(user);
}
private:
NationalPhoneRequest* nat_;
InterNationalPhoneRequest* internat_;
};