简体   繁体   English

传递复杂类型时的const-correctness

[英]const-correctness when passing complex types

So, I have four classes: 所以,我有四个班:

App - this represents the entry-point for the application 应用程序 - 这代表应用程序的入口点

MainPage - this represents the home screen MainPage - 这代表主屏幕

Authenticator - this represents a helper/utility class for authentication Authenticator - 这表示用于身份验证的帮助程序/实用程序类

LoginPage - this represents a login screen. LoginPage - 这表示登录屏幕。

App, MainPage, and LoginPage all have pointers to an Authenticator, and it is, in-fact, passed from App, to MainPage, to LoginPage as the user starts the app, reaches the main screen, and is prompted to log in. App creates MainPage, and if MainPage needs to log in, it creates LoginPage. App,MainPage和LoginPage都有指向Authenticator的指针,实际上,当用户启动应用程序,到达主屏幕并提示登录时,它实际上从App传递到MainPage,再传递给LoginPage。创建MainPage,如果MainPage需要登录,它会创建LoginPage。 The Authenticator pointer is passed at creation. Authenticator指针在创建时传递。

Let's say Authenticator looks something like this: 让我们说Authenticator看起来像这样:

class Authenticator {
public:
   std::string GetToken() const;
   void Login(std::string username, std::string pass);
}

Now, App will create a normal, non-const pointer to Authenticator but because I don't want MainPage to be able to modify Authenticator, I want it to store a const pointer to it (ie so it can only call const member functions on it). 现在,App将创建一个普通的,非const的指向Authenticator的指针,但因为我不希望MainPage能够修改Authenticator,我希望它存储一个const指针(即它只能调用const成员函数)它)。 However, I would like LoginPage to be able to call non-const member functions, like Login(), so when I pass my Authenticator from MainPage to LoginPage, I'll need to cast away the const-ness. 但是,我希望LoginPage能够调用非const成员函数,比如Login(),所以当我将我的Authenticator从MainPage传递给LoginPage时,我需要抛弃const-ness。

My question is : is it bad to do so in this situation? 我的问题是 :在这种情况下这样做是不是很糟糕? Should a class that is not allowed to modify an object be able to pass it to one that can? 一个不允许修改对象的类是否应该能够将它传递给一个可以的类? Or would it be better to have App create MainPage and LoginPage at the same time, and give them both the same Authenticator to start with? 或者让App同时创建MainPage和LoginPage更好,并给它们两个相同的Authenticator开始? My only problem with that option is that I create a LoginPage actively, rather than lazily, and I'd prefer to do it lazily. 我唯一的问题是我主动创建一个LoginPage,而不是懒惰,我宁愿懒洋洋地做。

Thanks in advance. 提前致谢。

From the Apps point of view, MainPage is modifying the Authenticator. 从Apps的角度来看,MainPage 正在修改Authenticator。 If it's doing so directly or calling another party (LoginPage) to do it on it's behalf doesn't matter. 如果它直接这样做或者呼叫另一方(LoginPage)代表它这样做并不重要。 So MainPage should get a non-const pointer and should then pass this to it's sub page for login. 所以MainPage应该得到一个非const指针,然后应该将它传递给它的子页面进行登录。

If you want to make sure that your MainPage does not modify the Authenticator, you could implement a base class for it that stores this pointer and has a method to call the login dialog. 如果要确保MainPage不修改Authenticator, 可以为它存储一个存储此指针的基类,并具有调用登录对话框的方法。 The Authenticator is private, the method is protected. Authenticator是私有的,方法受到保护。 You can then derive your own MainPageDerived which has no (legal, non-hacky) chance to modify Authenticator but can call LoginPage if needed. 然后,您可以派生自己的MainPageDerived,它没有(合法的,非hacky)修改Authenticator的机会,但如果需要可以调用LoginPage。

Note that I said could because for 3 classes I would think that's way overengineered. 请注意,我说可能是因为对于3个班级我会认为这是过度设计的。 However, if you have more pages in the future, that may be a valid approach. 但是,如果将来有更多页面,这可能是一种有效的方法。

You're missing an important part of the concept of logical constness. 你错过了逻辑常量概念的一个重要部分。 When a class accepts a pointer (or reference) to a const object, it's promising NEVER to use the pointer/reference in a way that could modify the object. 当一个类接受const对象的指针(或引用)时,它承诺永远不要以可以修改对象的方式使用指针/引用。 This of course means passing along to someone else who could modify it. 这当然意味着传递给可以修改它的其他人。

In other words, if MainPage is planning to ask someone to modify the Authenticator for it (that is, pass a non-const pointer to it to someone else), it's also responsible for the modifications, and should thus be storing a non-const pointer to it. 换句话说,如果MainPage计划要求某人为其修改Authenticator (即,将非const指针传递给其他人),它也负责修改,因此应该存储非const指向它的指针。

From an interface point of view: if you have MainPage( Authenticator const* ) , you are promessing that nothing MainPage does will modify the observable state of Authenticator . 从接口的角度来看:如果你有MainPage( Authenticator const* ) ,那么你可能会认为MainPage不会修改Authenticator的可观察状态。 Directly or indirectly—if MainPage later passes its pointer to another class which will modify the object, you've violated the contract. 直接或间接地 - 如果MainPage稍后将其指针传递给另一个将修改该对象的类,则您违反了该合同。 Thus, in your case, it const-correctness requires MainPage( Authenticator* ) : the code constructing MainPage doesn't care whether the modifications are direct or indirect; 因此,在您的情况下,它的const-correctness需要MainPage( Authenticator* ) :构造MainPage的代码不关心修改是直接的还是间接的; it just wants to know what the contract is, and that it is upheld. 它只是想知道合同是什么,并且它是坚持的。

Give MainPage only what it needs. 仅为MainPage所需内容。 You can look at this a few ways. 您可以通过以下几种方式来看待这一点。 It could need: 它可能需要:

  • An AuthenticationTokenSource which provides an up-to-date Token . AuthenticationTokenSource ,提供最新的Token
  • An AuthenticatedExectuor which performs Action s which MainPage defines, but AuthenticatedExectuor provides the authentication as it calls the Action AuthenticatedExectuor ,它执行MainPage定义的Action ,但AuthenticatedExectuor在调用Action提供身份验证

There are probably other ways, but those are the first that spring to mind. 可能还有其他方法,但这些是第一个让人想到的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM