1

在下面的代码中,我的意图是根据传递给 class 对象的参数调用kap(class )的两个重载构造函数之一:opacitymaterial

class opacity{
 private:
  int mode;
  double kap_const;
  double kappa_array[10][10];

 public:
  opacity(double constkap);  // picking the constructor sets the mode
  opacity(char* Datafile);
  double value(double T, double P); // will return a constant or interpolate
};

opacity::opacity(double constkap):mode(1){
  kap_const = constkap;
}

opacity::opacity(char* Datafile):mode(2){
  // read file into kappa_array...
}

class Matter {
 public:
  Matter(int i, double k, char* filename); // many more values are actually passed
  opacity kap;
  int x;  // dummy thing
  // more variables, call some functions
};

Matter::Matter(int i, double k, char * filename)
 :x(k>0? this->kap(x): this->kap(filename) ) {
  // ... rest of initialisation
 }

然而,这不起作用:

test.cpp: In constructor 'Matter::Matter(int, double, char*)':
test.cpp:32:21: error: no match for call to '(opacity) (void*&)'
test.cpp:32:42: error: no match for call to '(opacity) (char*&)'
test.cpp:32:44: error: no matching function for call to 'opacity::opacity()'
test.cpp:32:44: note: candidates are:
test.cpp:20:1: note: opacity::opacity(char*)
test.cpp:20:1: note:   candidate expects 1 argument, 0 provided
test.cpp:16:1: note: opacity::opacity(double)
test.cpp:16:1: note:   candidate expects 1 argument, 0 provided
test.cpp:4:7: note: opacity::opacity(const opacity&)
test.cpp:4:7: note:   candidate expects 1 argument, 0 provided

我尝试的第一件事,

Matter::Matter(int i, double k, char * filename)
 :kap(k>0? k: filename) {   // use k<0 as a flag to read from filename
  // ... rest of initialisation
}

也失败了,因为由于编译时原因,“三元运算符的结果总是必须是相同的类型”,正如在类似问题中指出的那样(尽管似乎没有在那里解释)。

Matter现在,不优雅的解决方案是也基于构造函数应该接收的参数重载构造kap函数,但这是(1)非常不优雅,特别是因为Matter构造函数需要许多变量并执行许多操作(所以很多代码会是复制只是为了改变构造函数初始化列表的一部分),并且(2)如果有另一个使用的类也有不同的构造函数,kap这可能会失控:对于具有N个 c'tors的M个类,一个以N结尾^ M组合...Matter

有人会有建议或解决方法吗?提前致谢!

4

4 回答 4

4

如果 opacity 有一个复制构造函数,您可以在初始化列表中完成此操作,避免使用默认构造函数,但以复制为代价:

  Matter::Matter(int i, double k, char * filename)
     :kap( ( 0 < k ) ? opacity(k) : opacity( filename ) ) { ... }
于 2011-10-06T18:38:07.503 回答
1

您将不得不忍受添加一个默认构造函数opacity(可能将模式设置0为指示无效模式)并kap在构造函数主体中分配给。

Matter::Matter(int i, double k, char * filename) {
  if(k > 0)
    kap = opacity(k);
  else
    kap = opacity(filename);
}

该参数k是运行时值。不可能使类型和重载结果依赖于运行时值。

于 2011-10-06T18:26:19.700 回答
1

为了避免复制开销,假设你有一个 C++0x 编译器,你可以给 opacity 一个移动构造函数opacity,并让一个静态函数根据你的逻辑提供一个实例,并kap使用返回的临时初始化你的成员opacity

您可能想要制作kappa_array一些指针,例如auto_ptr<double>. 尽管如果在紧密循环中使用此数据,与局部性和取消引用指针的成本相比,可移动性所节省的成本可能令人怀疑。

opacity& get_opacity(double k, char * filename) {
    if(k > 0)
        return opacity(k);
    else
        return opacity(filename);
}

Matter::Mater(int i, double k, char * filename)
    : kap(get_opacity(k, filename) {
   //...
}

opacity::opacity(opacity&& other)
    : mode(other.mode),
      kap_const(other.kap_const),
      kappa_array(std::move(kappa_array)) { }

请不要对此进行测试,我自己对移动语义和右值引用还是很陌生...

于 2011-10-06T18:44:19.123 回答
0

您不能使用三元运算符来选择函数覆盖,因为运算符的结果只有一种类型。在不同的分支有不同类型的情况下,它们将被强制为结果类型,否则会出现编译时错误。请参阅http://en.wikipedia.org/wiki/%3F:#Result_type

真的不可能是其他方式。编译器需要在编译时知道类型,但直到运行时才知道操作的结果。

于 2011-10-06T18:52:40.550 回答