2

我将不胜感激以下问题的解决方案:我有 2 种类型的变量

class Type1Str : public string
{
public:
  Type1Str(const string & str) : string(str) {}
};

class Type2Str : public string
{
public:
  Type2Str(const string & str) : string(str) {}
};

我想享受字符串的所有好处,但要防止交叉分配:

Type1Str t1; 
Type2Str t2;
t1 = t2;                           // <= should not be allowed
Type2Str t2_1(t1);                 // <= should not be allowed
Type2Str t2_2("a string");         // <= should be allowed

我怎样才能做到这一点?

4

3 回答 3

3

这应该可以解决问题:

#include <string>

using namespace std;

class Type2Str;

class Type1Str : public string
{
public:
    Type1Str() {}
    Type1Str(const std::string & str) : std::string(str) {}

private:
    Type1Str(const Type2Str &);  // deliberately private and unimplemented
    Type1Str & operator = (const Type2Str &);  // deliberately private and unimplemented
};

class Type2Str : public string
{
public:
    Type2Str() {}
    Type2Str(const std::string & str) : std::string(str) {}

private:
    Type2Str(const Type1Str &);  // deliberately private and unimplemented
    Type2Str & operator = (const Type1Str &);  // deliberately private and unimplemented
};

int main(int, char **)
{
   Type1Str t1;
   Type2Str t2;
   t1 = t2;                           // <= should not be allowed
   Type2Str t1_2(t1);                 // <= should not be allowed
   Type2Str t2_2("a string");         // <= should be allowed
   return 0;
}
于 2012-06-03T06:10:40.457 回答
2

只需将构造函数放入声明的私有/受保护部分:

class Type1Str : public string
{
    Type1Str(const class Type2Str&); // use forward declaration for class Type2Str
public:
    Type1Str(const string & str) : string(str) {}
};

class Type2Str : public string
{
    Type2Str(const Type1Str&); // this does not allow 'Type2Str t2_2(t1);'
public:
    Type2Str(const string & str) : string(str) {}
};
于 2012-06-03T06:09:41.073 回答
2

不幸的是,OP 提供了无法编译的代码。

这是以最自然的方式更正的原始代码,以便它编译:

class Type1Str : public string
{
public:
    Type1Str() {}
    Type1Str(const string & str) : string(str) {}
};

class Type2Str : public string
{
public:
    Type2Str() {}
    Type2Str(const string & str) : string(str) {}
};

假设上面的意思是,防止交叉分配所需要的就是制作转换构造函数explicit

#include <string>
using std::string;

class Type1Str : public string
{
public:
    Type1Str() {}
    explicit Type1Str(const string & str) : string(str) {}
};

class Type2Str : public string
{
public:
    Type2Str() {}
    explicit Type2Str(const string & str) : string(str) {}
};

int main()
{
    Type1Str t1; 
    Type2Str t2;

    t1 = t2;            // A. !Invalid, involves an implicit conversion.
    Type2Str t2_2(t1);  // B. Still allowed, here the conversion is explicit.
}

在标记为 B 的行中,调用的转换不是实际参数的隐式转换,而是Type2Str的显式转换构造函数。实际参数t1直接匹配该构造函数的形式参数,因为t2 std::string. OP 也想阻止 B 行。

一种简单的方法是使转换更加明确,即命名。

即,为形式参数引入载体类型,或引入额外的虚拟转换名称参数,或将公共转换构造函数替换为公共工厂函数。工厂函数是最简单的,并且截至 2012 年免费重新效率,但它有维护成本:派生类必须重新实现它才能提供该功能。在这里提到的其他两个解决方案中,额外的虚拟名称参数是最容易实现且代码最少的:

#include <string>
using std::string;

namespace from { enum StdString { stdString }; };

class Type1Str : public string
{
public:
    Type1Str() {}
    Type1Str( from::StdString, const string & str) : string(str) {}
};

class Type2Str : public string
{
public:
    Type2Str() {}
    Type2Str( from::StdString, const string & str) : string(str) {}
};

int main()
{
    Type1Str t1; 
    Type2Str t2;
    Type2Str t3( from::stdString, t1 ); // OK.

    t1 = t2;            // A. !Invalid, no conversion possible.
    Type2Str t2_2(t1);  // B. !Invalid, no conversion possible.
}

那么,仅仅为所有想要禁止直接复制的类型声明私有构造函数和赋值运算符有什么问题呢?

好吧,除了脆弱之外,对于n类型的声明,它相当于 O( n 2 )。所以这通常不是一个好主意。然而,在我写这篇文章时,OP 选择了一个采用这种方法的答案作为“解决方案”。请注意:总的来说,这真的不是一个好主意。

于 2012-06-03T07:02:50.473 回答