我正在尝试为项目的某些类创建类似于命名参数的构造函数。
我这样做的方法是定义一个类代理,它将保存参数并将此代理的实例传递给我的类的构造函数。
一切正常,直到我必须派出我的一个班级。
基本上我想:我要从基类代理派生新的派生类代理。这也有效,但前提是我只使用派生的代理类参数。
这是一个例子,因为它更容易理解:
class Person
{
public:
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
}
public:
Person()
: _name("")
, _surname("")
{ }
Person(const PersonArgs& args)
: _name(args.Name())
, _surname(args.Surname())
{ }
protected:
std::string _name;
std::string _surname;
}
class PersonEx : public Person
{
public:
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
}
public:
PersonEx()
: _address("")
{ }
PersonEx(const PersonExArgs& args)
: Person(args)
, _address(args.Address())
{ }
protected:
std::string _address;
}
int main(int argc, char** argv)
{
// This is ok since PersonExArgs::Address returns a PersonExArgs&
PersonEx* p1 = new PersonEx(PersonEx::PersonExArgs().Address("example"));
// This won't work since PersonExArgs::Name returns a PersonArgs&
PersonEx* p2 = new PersonEx(PersonEx::PersonExArgs().Address("example").Name("Mark"));
}
基本上,因为我在设置参数时链接返回对代理类实例的引用的参数,所以当从派生代理类使用它时它会中断,因为它将返回对基本代理类的引用而不是派生代理类的引用,不允许我访问派生的代理参数,也不将其传递给派生类的构造函数。
任何人都知道如何解决这个问题?
答案 0 :(得分:1)
此问题最常见的解决方案是奇怪的重复模板模式(CRTP):
template <typename Derived>
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
const std::string& Surname() const { return _surname; }
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
protected:
std::string _name;
std::string _surname;
};
...
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
};
在您的情况下,您可以将它与另一个基类组合以清理界面:
class Person {
class PersonArgsBase
{
public:
const std::string& Name() const { return _name; }
const std::string& Surname() const { return _surname; }
protected:
std::string _name;
std::string _surname;
};
template <typename Derived>
class PersonArgs : public PersonArgsBase
{
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
};
...
};
class PersonEx {
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
...
};
};
答案 1 :(得分:1)
也许协变返回类型正是您所寻找的 有关详细信息,请参阅here。
您可以将PersonArgs
定义为(注释virtual
个关键字):
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
virtual PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
virtual PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
};
然后将PersonExArgs
定义为(注意override
和协变返回类型):
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
PersonExArgs& Name(const std::string& name) override
{
PersonArgs::Name(name);
return *this;
}
PersonExArgs& Surname(const std::string& surname) override
{
PersonArgs::Surname(surname);
return *this;
}
protected:
std::string _address;
};
你必须覆盖基类中的每一个函数,但它可以很好地工作,这很烦人。 在wandbox上查看并运行。