在我的C ++类中,我想防止某些成员函数能够被调用,具体取决于使用哪个构造函数创建对象,并且如果尝试这样做,则会导致编译时错误。
一些上下文:
我的项目中已有一个广泛使用的类,该类用于读取/写入数据库。有时,当我创建此类的实例时,我只想从数据库中读取数据,因此,我想创建一个新的构造函数,该构造函数是一个“只读”构造函数,可防止所有写入数据库的函数从做任何事情。 (我这样做的原因是,如果对象要向其写入数据,我想从被访问的数据库中“锁定”该行,但是如果该对象仅从数据库中读取,则不这样做。)
当然,要防止成员函数在运行时基于使用哪个构造函数执行任何操作,这并不是很困难。例如:
class DatabaseInterface
{
private:
bool readOnly;
public:
// Constructor #1
// This constructor allows read only from database
DatabaseInterface(int x)
{
readOnly = true;
// Do something
}
// Constructor #2
// This constructor allows read/write to database
DatabaseInterface(int x, bool y)
{
readOnly = false;
// Do something
}
void UpdateDatabase()
{
if (readOnly) return;
// Update Database
}
};
通过此类,您可以执行以下操作:
DatabaseInterface A(5);
DatabaseInterface B(5,true);
A.UpdateDatabase(); // Does nothing
B.UpdateDatabase(); // Updates database
但是有没有办法修改此类,使得上面的A.UpdateDatabase()
会导致编译时错误?
我的想法是(由于类的所有实例当前都使用带有一个参数的构造函数),如果我可以为此强制执行编译时错误,那么我可以确保该类的所有实例都将使用正确的构造函数,因为如果试图在使用“只读”构造函数创建的对象上使用“书写”功能,它甚至都不会编译。
我想知道这是否可行,因为请注意,只要它是bool
类型,构造函数中第二个参数的 value 都无关紧要。
答案 0 :(得分:3)
如果您愿意将类作为模板,则可以使用标签来创建只读的DatabaseInterface
或读写的DatabaseInterface
。看起来像
struct read_only_t{};
struct read_write_t{};
template<typename T>
class DatabaseInterface
{
public:
DatabaseInterface(int x)
{
// Do something
}
void UpdateDatabase()
{
static_assert(!std::is_same_v<T, read_only_t>, "DatabaseInterface is in read only mode");
// Update Database
}
};
现在,如果您尝试在UpdateDatabase
上调用DatabaseInterface<read_only_t>
答案 1 :(得分:1)
是的,只要愿意为DatabaseInterface
类创建模板,就可以使它在编译时失败。
例如,您需要添加bool类型的模板参数,然后仅将UpdateDatabase()
函数专用于<true>
的模板参数值。当您尝试在参数为UpdateDatabase()
的对象上调用<false>
函数时,编译器会抱怨该函数已声明,但未定义。
答案 2 :(得分:1)
您可以为此使用继承:
class ReadOnlyDBI {
public:
void readData();
virtual ~ReadOnlyDBI();
};
class ReadWriteDBI : public ReadOnlyDBI {
public:
void writeData();
};
void someFunctionReadingData( ReadOnlyDBI &dbi )
{
dbi.readData(); // fine
dbi.writeData(); // error, this function can only read
}
void foo()
{
ReadWriteDBI rwd;
rwd.readData(); // fine to read from it
someFunctionReadingData( rwd ); // we can pass it to a func that reads
rwd.writeData(); // we can write
}
否则,您还必须写someFunctionReadingData
作为模板。