abyss.7
abyss.7

Reputation: 14462

Is it possible to construct only const objects of specific type in C++?

I want to implement the class with the following properties:

class A { ... };

const A a;  // ok - should work.
A b;        // compilation error - shouldn't work!

Also, it would be better, if the constness of an object depends on the constructors signature:

const A c(1);  // ok - should work.
A d("a");      // ok - should work.
A e(2);        // compilation error - shouldn't work!

Usage of C++11 is allowed, if required.


Update #1

Since I don't know the answer, it's not required to strictly follow the code above - any C++ pattern providing similar semantics is welcome.

Upvotes: 4

Views: 216

Answers (4)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136405

You can do that with an extra constructor argument which is a reference to self, e.g.:

class X {
public:
    X(X const& self) {
        assert(this == &self);
    }

private:
    X(X&);
};

And then invoke it like so:

X const x(x); // works
X y(y); // fails to compile
X z(x); // fails at run-time

Upvotes: 1

Avt
Avt

Reputation: 17043

1.You can create class with only const methods and private members.

2.You can create "normal" class but declare its constructor as private. Then you will need a friend-class with following method (or something similar)

class ConstClassProvider{
public:
    static const A* getA(/* you can have params here*/)
    {
        return new A();
    }
}

so

A a1;//error
const A a2;//error
A *a3 = ConstClassProvider::getA(); //error
const A *a4 = ConstClassProvider::getA(); //ok!

Upvotes: 5

KonstantinL
KonstantinL

Reputation: 667

Probably this is you are looking for:

class AData {
public:
    AData() : intValue( 0 ), stringValue( 0 ) {}
    void SetInt( int arg ) { intValue = arg; }
    void SetString( const char* arg ) { stringValue = arg; }

private:
    int intValue;
    const char* stringValue;
};

class A {
public:
    A();
    void Init( int intValue ) const;
    void Init( const char* stringValue );

private:
    AData* p;
};

A::A() : p( new AData )
{
}

void A::Init( int intValue ) const
{
    p->SetInt( intValue );
}

void A::Init( const char* stringValue )
{
    p->SetString( stringValue );
}

Upvotes: 0

Dennis
Dennis

Reputation: 3731

You need to make an immutable class. In other words use encapsulation to prevent users of your class from setting any fields.

Basically:

class Immutable{
private:
  const int intField;
  const std::string textField;
public:
  Immutable(const std::string& ref, int copy) : intField{copy}, testField{ref} {}
  int getIntField(){return intField;}
  const std::string& getTextField(){ return textField; }
}

Then just don't expose your internals via setters.

Upvotes: 2

Related Questions