1

読みやすくするために、クラスを最小限にカットします。

#ifndef MESSAGEFOLDER
#define MESSAGEFOLDER

#include <string>
#include <set>

class Message;

class Folder{
public: 
    void addMsg(Message* m) { messages.insert(m); } 
    ~Folder() { removeFromMessages(); }
private:
    std::set<Message*> messages;
    void removeFromMessages(); //removes its pointers from Messages
};

class Message{
    friend class Folder;
public:
    Message(const std::string &s = ""): contents(s) { }
    Message(const Message& rhs): contents(rhs.contents), folders(rhs.folders) { addToFolders(); }
    Message& save(Folder&); 
    ~Message() { removeFromFolders(); }
private:
    std::string contents;
    std::set<Folder*> folders;
    void addToFolders();
    void removeFromFolders(); //removes its pointers from Folders
};


#endif // MESSAGEFOLDER

MessageFolder.cpp 内

void Message::addToFolders(){
    for(const auto& f : folders)
        f->addMsg(this);
}

Message& Message::save(Folder& f){
    folders.insert(&f);
    f.addMsg(this);
    return *this;
}

このコードはconstmessages. のコンストラクターは、ポインターMessageを想定していません。したがって、コードは関数ではありませんがconstthisaddToFoldersconst

Message a("hello");
Folder f;
a.save(f);
const Message b(a);

正常にコンパイルされます。bconstメッセージですが、コピー コンストラクターはbのアドレスを ( を介してaddToFolders()) から構成されるフォルダーにset設定するため、ここに問題があります。Message*低レベルconstが失われます。Folder実際、基になるメッセージを変更する関数を定義すると、コンパイル エラーなしでcontentsconst メッセージを変更できます。b

解決策は、Folderの設定をset<const message*>に変更することですが、これにより、フォルダーを介してメッセージを変更できなくなります (これは実際に望んでいます)。const オブジェクトが作成されるのを防ぐにはどうすればmessageよいですか? あるいは、thisコンストラクター内のポインターが失敗するconstように強制するにはどうすればよいでしょうか?addToFolders()

4

1 に答える 1

2

constインスタンスの構築を防ぐことはできません。

コンストラクターで使用する場合this、適切に注意するのはあなた次第です。たとえば、明示的const_castに aにすることができます。const *

一般に、オブジェクトの管理がオブジェクト自体のクラス内で処理されない方がうまく機能します。folderたとえば、 オブジェクトを 経由でのみ作成できるように制限し、 でオブジェクトがfolder正しく処理されるようにすることができます。(これは実際には関心の分離の単なる例です。)

于 2015-08-31T16:59:48.487 に答える