CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    May 2011
    Posts
    45

    C4677, mixing private and public ??

    I’m creating a Windows Form application as a tool for website development. The initial form maintains a list of user defined website names paired with the local path to the files that make up the site. The path points to the base directory of the site and that base directory should contain certain sub-directories for use by the eventual process.

    I’ve created a website class to maintain the data and path related to each website. This class implements IComparable so the list can be kept in alphabetic order:
    website.h:

    Code:
    #pragma once
    using namespace System;
    
    ref class website  : public IComparable
    {
    public:
    	website(void);
    	website(String ^name, String ^path);
    	bool operator < (website^);
    	bool CheckDirectory();
    	String^ domainName;
    	String^ localPath;
    	int pathCount;
    	int clientFlag;
    	int archiveFlag;
    	int serverFlag;
    	int webFlag;
    
    	virtual Int32 CompareTo ( Object ^ obj)
    	{
    		website ^ other;
    		other = (website ^)obj;
    		if ( other == nullptr ) return 0;
    		int i = 0;
    		while ( ( i < domainName->Length ) && ( i < other->domainName->Length ) )
    		{
    			if (System::Char::ToLower(domainName[i]) < System::Char::ToLower(other->domainName[i]) ) 
    				return -1;
    			else if (System::Char::ToLower(domainName[i]) > System::Char::ToLower(other->domainName[i]) ) 
    				return 1;
    			i++;
    		}
    		if ( domainName->Length > other->domainName->Length ) 
    			return 1;
    		return -1;
    	}
    
    };
    website.cpp:

    Code:
    #include "StdAfx.h"
    #include "website.h"
    #include "NoBaseDirectory.h"
    #include "NeedSubDirectories.h"
    
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	using namespace System::IO;
    
    	using namespace Sites;
    
    
    website::website(void)
    {
    }
    website::website(String ^name, String ^path)
    {
    	domainName  = name;
    	localPath   = path;
    	pathCount   = 0;
    	clientFlag  = 0;
    	archiveFlag = 0;
    	serverFlag  = 0;
    	webFlag     = 0;
    
    }
    bool website::operator < (website^ param) {
    	int i = 0;
    	while ( ( i < domainName->Length ) && ( i < param->domainName->Length ) )
    	{
    		if (System::Char::ToLower(domainName[i]) < System::Char::ToLower(param->domainName[i]) ) 
    			return true;
    		else if (System::Char::ToLower(domainName[i]) > System::Char::ToLower(param->domainName[i]) ) 
    			return false;
    		i++;
    	}
    	if ( domainName->Length < param->domainName->Length ) 
    		return true;
    	return false;
    }
    
    bool website::CheckDirectory()
    {
    	for(;;)
    	{
    		if ( Directory::Exists( localPath ) )
    		{
    			DirectoryInfo ^ myDir = gcnew DirectoryInfo(localPath);
    			array<DirectoryInfo^>^ files = myDir->GetDirectories("*.*");
    			for ( int idx = 0 ; idx < files->Length ; idx ++ )
    			{
    				String ^ subDir = files[idx]->Name;
    				if (subDir->ToLower() == "client")
    					clientFlag = 1;
    				if (subDir->ToLower() == "client.arc")
    					archiveFlag = 1;
    				if (subDir->ToLower() == "web")
    					webFlag = 1;
    				if (subDir->ToLower() == "server")
    					serverFlag = 1;
    				int k = 1;
    			}
    			pathCount = clientFlag + archiveFlag + webFlag + serverFlag + 1;
    			if ( pathCount != 5)
    			{
    				NeedSubDirectories ^ getSubs = gcnew NeedSubDirectories ( domainName , localPath , this );
    				getSubs->ShowDialog();
    			}
    			return true;
    		}
    		else
    		{
    			pathCount = 0;
    			NoBaseDirectory ^ noDir = gcnew NoBaseDirectory( domainName , localPath );
    			noDir->ShowDialog();
    			if (noDir->pathChanged->Equals(true))
    			{
    				localPath = noDir->newLocalPath;
    				continue;
    			}
    
    			return false;
    		}
    	}
    }
    The main form calls the CheckDirectory method to insure the path and subdirectories exist. If any of the sub-directories is missing it pops up a form to ask if the user wants to create the missing directories.

    NeedSubDirectories.h

    Code:
    #pragma once
    
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::IO;
    using namespace System::Drawing;
    
    #include "website.h"
    
    namespace Sites {
    
    	/// <summary>
    	/// Summary for NeedSubDirectories
    	///
    	/// WARNING: If you change the name of this class, you will need to change the
    	///          'Resource File Name' property for the managed resource compiler tool
    	///          associated with all .resx files this class depends on.  Otherwise,
    	///          the designers will not be able to interact properly with localized
    	///          resources associated with this form.
    	/// </summary>
    	public ref class NeedSubDirectories : public System::Windows::Forms::Form
    	{
    	private: website ^ WebSite;
    	public:
    		NeedSubDirectories ( String ^ site , String ^ path , website ^ newSite)
    		{
    			InitializeComponent();
    			WebSite = newSite;
    			this->WebName->Text = site;
    			this->LocalPath->Text = path;
    			if ( newSite->clientFlag == 0 )
    			{
    				ClientOK->Text = "Missing";
    				ClientOK->ForeColor = System::Drawing::Color::Firebrick;
    			}
    			else
    			{
    				ClientOK->Text = "OK";
    				ClientOK->ForeColor = System::Drawing::Color::Green;
    			}
    			if ( newSite->archiveFlag == 0 )
    			{
    				ArchiveOK->Text = "Missing";
    				ArchiveOK->ForeColor = System::Drawing::Color::Firebrick;
    			}
    			else
    			{
    				ArchiveOK->Text = "OK";
    				ArchiveOK->ForeColor = System::Drawing::Color::Green;
    			}
    			if ( newSite->serverFlag == 0 )
    			{
    				ServerOK->Text = "Missing";
    				ServerOK->ForeColor = System::Drawing::Color::Firebrick;
    			}
    			else
    			{
    				ServerOK->Text = "OK";
    				ServerOK->ForeColor = System::Drawing::Color::Green;
    			}
    			if ( newSite->webFlag == 0 )
    			{
    				WebOK->Text = "Missing";
    				WebOK->ForeColor = System::Drawing::Color::Firebrick;
    			}
    			else
    			{
    				WebOK->Text = "OK";
    				WebOK->ForeColor = System::Drawing::Color::Green;
    			}
    
    			//
    			//TODO: Add the constructor code here
    			//
    		}
    
    	protected:
    		/// <summary>
    		/// Clean up any resources being used.
    		/// </summary>
    		~NeedSubDirectories()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    	private: System::Windows::Forms::Label^  WebName;
    	private: System::Windows::Forms::Label^  LocalPath;
    	private: System::Windows::Forms::Label^  label1;
    	private: System::Windows::Forms::Label^  label2;
    	private: System::Windows::Forms::Label^  label3;
    	private: System::Windows::Forms::Label^  label4;
    	private: System::Windows::Forms::Label^  label5;
    	private: System::Windows::Forms::Label^  ClientOK;
    	private: System::Windows::Forms::Label^  WebOK;
    	private: System::Windows::Forms::Label^  ServerOK;
    	private: System::Windows::Forms::Label^  ArchiveOK;
    	private: System::Windows::Forms::Label^  label10;
    	private: System::Windows::Forms::Label^  label11;
    	private: System::Windows::Forms::Label^  label12;
    	private: System::Windows::Forms::Label^  label13;
    	private: System::Windows::Forms::Button^  button1;
    	private: System::Windows::Forms::Button^  button2;
    	protected: 
    
    
    	private:
    		/// <summary>
    		/// Required designer variable.
    		/// </summary>
    		System::ComponentModel::Container ^components;
    
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Required method for Designer support - do not modify
    		/// the contents of this method with the code editor.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->WebName = (gcnew System::Windows::Forms::Label());
    			this->LocalPath = (gcnew System::Windows::Forms::Label());
    			this->label1 = (gcnew System::Windows::Forms::Label());
    			this->label2 = (gcnew System::Windows::Forms::Label());
    			this->label3 = (gcnew System::Windows::Forms::Label());
    			this->label4 = (gcnew System::Windows::Forms::Label());
    			this->label5 = (gcnew System::Windows::Forms::Label());
    			this->ClientOK = (gcnew System::Windows::Forms::Label());
    			this->WebOK = (gcnew System::Windows::Forms::Label());
    			this->ServerOK = (gcnew System::Windows::Forms::Label());
    			this->ArchiveOK = (gcnew System::Windows::Forms::Label());
    			this->label10 = (gcnew System::Windows::Forms::Label());
    			this->label11 = (gcnew System::Windows::Forms::Label());
    			this->label12 = (gcnew System::Windows::Forms::Label());
    			this->label13 = (gcnew System::Windows::Forms::Label());
    			this->button1 = (gcnew System::Windows::Forms::Button());
    			this->button2 = (gcnew System::Windows::Forms::Button());
    			this->SuspendLayout();
    			// 
    			// Component initialization removed to stay in 20000 char limit
    			// 
    			this->ResumeLayout(false);
    			this->PerformLayout();
    
    		}
    #pragma endregion
    	private: System::Void NeedSubDirectories_Load(System::Object^  sender, System::EventArgs^  e) {
    			 }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
    			 this->Close();
    		 }
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    			 // Create the missing directories
    			 if (WebSite->clientFlag == 0)
    			 {
    				 String ^ newDir = gcnew String(WebSite->localPath + "\\Client");
    				 if ( System::IO::Directory::CreateDirectory(newDir) )
    					WebSite->clientFlag = 1;
    			 }
    			 if (WebSite->archiveFlag == 0)
    			 {
    				 String ^ newDir = gcnew String(WebSite->localPath + "\\Client.arc");
    				 if ( System::IO::Directory::CreateDirectory(newDir) )
    					 WebSite->archiveFlag = 1;
    			 }
    			 if (WebSite->serverFlag == 0)
    			 {
    				 String ^ newDir = gcnew String(WebSite->localPath + "\\Server");
    				 if ( System::IO::Directory::CreateDirectory(newDir) )
    					 WebSite->serverFlag = 1;
    			 }
    			 if (WebSite->webFlag == 0)
    			 {
    				 String ^ newDir = gcnew String(WebSite->localPath + "\\Web");
    				 if ( System::IO::Directory::CreateDirectory(newDir) )
    					 WebSite->webFlag = 1;
    			 }
    			 this->Close();
    			 WebSite->pathCount =  WebSite->clientFlag + WebSite->archiveFlag +
    								   WebSite->serverFlag + WebSite->webFlag + 1 ;
    		 }
    };
    }
    I need to remember the reference to the website in the sub-form so the process can create the proper directories if the user requests them, but I keep getting warnings/error messages when I move the WebSite member variable around. The previous code has only warnings, and runs, but I’d like to find out the proper syntax so I can eliminate the warnings.

    Code:
    Compiling...
    website.cpp
    NeedSubDirectories.h(26) : warning C4677: 'WebSite': signature of non-private member contains assembly private type 'website'
                website.h(4) : see declaration of 'website'
    NeedSubDirectories.h(28) : warning C4677: 'NeedSubDirectories': signature of non-private member contains assembly private type 'website'
                website.h(4) : see declaration of 'website'
    NeedSubDirectories.cpp
    NeedSubDirectories.h(26) : warning C4677: 'WebSite': signature of non-private member contains assembly private type 'website'
                website.h(4) : see declaration of 'website'
    NeedSubDirectories.h(28) : warning C4677: 'NeedSubDirectories': signature of non-private member contains assembly private type 'website'
                website.h(4) : see declaration of 'website'
    Generating Code...
    Linking...
    Sites - 0 error(s), 4 warning(s)
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

  2. #2
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: C4677, mixing private and public ??

    You get the C4677 warning because the parameter list of your NeedSubDirectories constructor, that is part of this public class' public interface, contains a parameter of type website ^, which is a private class (in the absence of a class accessibility specifier, C++/CLI defaults to private). (I have no idea, though, why you get the same warning for the declaration of the private member in line 26.) Since it probably isn't planned to ever access the classes in this assembly from outside of the assembly (and this is the only scenario where the trouble C4677 warns you of actually could arise), class accessibility doesn't really matter, so you can simply fix the warning by making website a public class.

    BTW, the "mix of private and public" mentioned in the title of this thread is actually possible by using the C++/CLI-specific (i.e. unavailable in native C++) access specifier internal. A member with this visibility is public inside the assembly defining the class containing that member, but private to the outside world. However, this specifier can only be applied to members, not to classes.

    BTW2, your implementation of website::CompareTo() never (exception see below) returns equality, not even when comparing a website instace to itself. I'm not sure that would ever actually cause trouble with any of the .NET collections, but I wanted to mention it. The exception: It does return equality (i.e. 0) when comparing to nullptr. And this obviously is wrong according to basic logic: Your website instance that CompareTo() is called on can in no way be nullptr itself. The reference implementation on MSDN (see http://msdn.microsoft.com/en-us/libr...omparable.aspx) returns 1 in this case, which makes sense, because it means that nullptr always is less than any existing instance of the class.

    Also, I'm not entirely sure how C++/CLI interprets the C-style cast you apply to obj, but I suspect it turns it into a static_cast which is dangerous in case anyone happens to pass anything else than a website ^ or nullptr to your implementation. You may not want to get as fancy as the reference implementation and gcnew your own exception object, but I'd suggest to at least use a safe_cast instead that will throw an InvalidCastException on its own when someone calls that method, passing an incompatible object. (That is, BTW, one of the main reasons why I usually prefer to implement IComparable<T> rather than IComparable.)
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #3
    Join Date
    May 2011
    Posts
    45

    Re: C4677, mixing private and public ??

    I fixed the CompareTo() issues, but am still lost on the casting.

    When I change the code to:

    Code:
    	virtual Int32 CompareTo ( website ^ other)
    	{
    I get the error:

    [code]Error 1 error C3766: 'website' must provide an implementation for the interface method 'int System::IComparable::CompareTo(System::Object ^)' website.h 46 Sites{/code]

    Which is why I change the code to re-cast the “Object” reference:

    Code:
    	virtual Int32 CompareTo ( Object ^ obj)
    	{
    		website ^ other;
    		other = (website ^)obj;
    Is there a better way to do the re-casting?

    I’m still lost on the initial question. When the website class performs it’s Check Directory function and determines that the sub-directory structure is incomplete, I need to pop up a form and ask the user if they want the sub-directory(s) built for them. The form actually builds the directories when the user says “build them”. In that case the form needs to know what to build and where to build them. That is all contained in the website class.

    The call to the form uses “this” to pass the current website data to the form.
    Code:
    NeedSubDirectories ^ getSubs = gcnew NeedSubDirectories ( domainName , localPath , this );
    getSubs->ShowDialog();
    And the button click is caused by an event, so the website class needs to the remembered by the form in case the “build them” button is hit.

    The code works as is, but gets the warnings. What is the proper syntax to eliminate the warnings?

  4. #4
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: C4677, mixing private and public ??

    Quote Originally Posted by PapaGeek View Post
    When I change the code to:

    Code:
    	virtual Int32 CompareTo ( website ^ other)
    	{
    I get the error:

    [code]Error 1 error C3766: 'website' must provide an implementation for the interface method 'int System::IComparable::CompareTo(System::Object ^)' website.h 46 Sites{/code]
    In order for that to work, you need to change your class definition to derive from the generic comparable interface (see http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx):

    Code:
    public ref class website : public IComparable<website ^>
    {
    
    // ...
    
    };
    (The bit in blue is explained at the end of the post.)

    Despite the equal name, the generic and non-generic comparable interfaces are distinct, just like CompareTo(Object ^) and CompareTo(website ^) are distinct overloads of the same method (though inherited from distinct interfaces). You may very well implement both the generic and non-generic versions, though I myself never have seen a reason for that. AFAIK the default comparer used by the non-generic collections contains a CompareTo(Object ^) implementation that is able to make use of the generic CompareTo() implementation of the type it is applied to. (Can't find the place on MSDN where that is documented, though, at the moment.)

    Which is why I change the code to re-cast the “Object” reference:

    Code:
    	virtual Int32 CompareTo ( Object ^ obj)
    	{
    		website ^ other;
    		other = (website ^)obj;
    Is there a better way to do the re-casting?
    Casting is ok here. In fact, there's no way to avoid it in the non-generic CompareTo() implementation. The MSDN reference implementation, of course, does that too, though they use a dynamic_cast instead of the safe_cast I suggested. The difference between these two approaches is that their use of dynamic_cast will raise a NullReferenceException if an incompatible object is passed to CompareTo(), while the safe_cast will raise an InvalidCastException. You should always use either of these approaches since that is the only way to ensure runtime type-safety. (Actually, there are other ways to do that, but IMO they don't gain anything bersides complicating the code, so they are of rather academic interest.)

    I’m still lost on the initial question. [...]

    [...]

    The code works as is, but gets the warnings. What is the proper syntax to eliminate the warnings?
    I explained that right at the beginning of post #2: Turn website into a public refernece class instead of the private class it is now. I have demonstrated the change in the snippet at the beginning of this post.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  5. #5
    Join Date
    May 2011
    Posts
    45

    Re: C4677, mixing private and public ??

    Thanks Eri,

    This site, and members like yourself, are extremely helpful.

    Code:
    public ref class website : public IComparable<website ^>
    is the syntax that solved all my problems!

    I’ve been a “C” programmer since the 1970’s using the first edition K&R C book as a guide. The second addition of their book was ANSI C. Before C I programmed in assembler and Fortran IV. Hence the “Papa” in my log on name.

    I wrote my first Unix Windows application in “C” using structs to manage the buttons, labels, lists, (objects) long before they introduced classes in C++.

    Moving to managed C++ to work with forms has been a chore, but the help I get on this site has made it much easier. But, I have to ask one last question: A lot of the developers that I work with are telling me to give up on managed C++ and move directly into C#. So, are they correct? Is C++ a dying language that is being replaced by C#? Should I abandon my current path and learn the C# syntax?

    Thanks again for all your help. Plan A is to stick with C++, but I could be swayed by someone who knows BOTH languages.

  6. #6
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: C4677, mixing private and public ??

    Quote Originally Posted by PapaGeek View Post
    Thanks Eri,
    You're welcome!

    I’ve been a “C” programmer since the 1970’s using the first edition K&R C book as a guide. The second addition of their book was ANSI C. Before C I programmed in assembler and Fortran IV. Hence the “Papa” in my log on name.
    Interesting. Actually, I happened to use the K&R book myself when I learned C, what was sometime around the mid-80s though. But since AFAIK the ANSI standard wasn't settled before '89 it probably was the 1st edition if the 2nd one already had been "ANSIfied". I still recall that creepy K&R syntax for the declaration of function parameter lists...

    Moving to managed C++ to work with forms has been a chore, but the help I get on this site has made it much easier. But, I have to ask one last question: A lot of the developers that I work with are telling me to give up on managed C++ and move directly into C#. So, are they correct? Is C++ a dying language that is being replaced by C#? Should I abandon my current path and learn the C# syntax?

    Thanks again for all your help. Plan A is to stick with C++, but I could be swayed by someone who knows BOTH languages.
    Actually, the vast majority of arrived developers aroud here will give you the same recommendation, and even I understand why they do so. My own preference for C++/CLI is definitely anti-mainstream. C# definitely does have its advantages like the integration of extension methods or the LINQ query definition syntax. While extension methods can pretty much be used in C++/CLI as well once you found out how that is done (and that's somewhat hard to find on MSDN - IIRC I, myself, found the simple trick in a blog post, more accidentally than not), LINQ queries are practically impossible in C++/CLI. The underlying .NET infrastructure is available and allows to do some fancy tricks, but the query definition syntax is not. That way writing LINQ queries in C++/CLI and C# is worlds apart and C# wins hands-down in this discipline.

    The mainstream opinion about C++/CLI is that its only real use is managed/native interop. But while I agree that this in fact is C++/CLIs dominant and unique strength, IMO it is a viable general-purpose language as well.

    One thing, for instance, I don't like that much about C# is that it tends to obscure more what's actually going on unter the hood than C++/CLI. E.g., its syntax for using value types vs. reference types is mostly identical, with the exception of their definition (value types are called struct there and reference types class) and the fact that reference types need to be instantiated with new. In C++/CLI, OTOH, the distinction between the two is syntactically ubiquotious and impossible to overlook (with the exception of implicitly dereferenced variables which, though, seems to be a hardly known and rarely used feature anyway).

    Many HLL programmers nowadays seem to be perfectly comfortable with not knowing the low-level details, however, assembly language guys like you and me are somewhat likely to view that differently...

    I can't really claim I know both languages. I'm just able to half-way decently read C# which is almost mandatory because lots of code samples simply aren't available in C++/CLI. I doubt I'm able to half-way fluently write C#, though.

    Perhaps you'll get some more rather mainstream comments on this thread as well. The guys who really do know both languages or at least know C++/CLI about as good as I know C# come around here from time to time too (and I definitely appreciate that ). They're just less regular here than I am.
    Last edited by Eri523; January 5th, 2012 at 06:24 PM.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured