LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-28-2009, 12:17 AM   #1
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148
Blog Entries: 1

Rep: Reputation: 48
Question Regarding C++ Visibility


Okay, so in an examination of nested classes in C++, I came upon this interesting problem. The following code compiles with no warnings with "-Wall -Wextra -ansi -pedantic" on gcc and "-Wall -Wcheck" on icc, leading me to believe that it is valid C++.

Code:
#include <iostream>

class Outer{
  private:
    struct Inner { 
      int i;
      void print() { std::cout << i << std::endl; }
    };

  public:
    static Inner do_stuff() { Inner i = { 5 }; return i; }
};

int main()
{
  Outer::do_stuff().print();  //This works
  //Outer::Inner inner = do_stuff();  //This does not
  //inner.print();

  return 0;
}
If this code is run, it prints 5, exactly as expected.

My question is, why should this work? Outer::Inner is private, so it's print member function should not be visible to main. Indeed, one does get a compiler error if one switches out the commented lines with the one above them.

Any insight on why this is? Is there some situation I'm not foreseeing in which this behavior is desirable?
 
Old 08-28-2009, 12:36 AM   #2
irkkaaja
Member
 
Registered: Oct 2008
Posts: 44

Rep: Reputation: 16
Outer::dostuff() returns an Inner object. This object can call print, since it is allowed to access its own members. print() is actually public for this object; it is Inner which is private. main() can therefore call print() without any problems, though it is not allowed to declare a variable of type Inner, since it cannot "see" Inner. It works because C++ is weakly typed; instead of performing a typecheck on Outer::dostuff() at runtime, it just looks to see if it has a print() method, which it does. I'm pretty sure if you assigned Outer::dostuff() to a variable of type Object, or whatever C++'s basic object class is (sorry, I don't know much about C++), and then called print(), it wouldn't complain.

In other words, main() has no idea that it is calling Inner's print method, it is just calling something's print method.
http://en.wikipedia.org/wiki/Weak_typing

I'm pretty sure this would return a compiler error in a strongly-typed language like Ada or Java.

Last edited by irkkaaja; 08-28-2009 at 12:37 AM.
 
Old 08-28-2009, 12:46 AM   #3
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by irkkaaja View Post
It works because C++ is weakly typed; instead of performing a typecheck on Outer::dostuff() at runtime, it just looks to see if it has a print() method, which it does.
I'm relatively sure that is not how this works. C++ is very statically typed, so the compiler knows the (compile-time) type of Outer::do_stuff() at compile time. Since print() is non-virtual, the call to print is bound at compile time, not runtime.

Quote:
I'm pretty sure if you assigned Outer::dostuff() to a variable of type Object, or whatever C++'s basic object class is (sorry, I don't know much about C++), and then called print(), it wouldn't complain.
C++ doesn't have such a class. Unlike Java, C++ has no requirement that there exist a singly-rooted inheritance tree, rather C++ has an inheritance not-necessarily-connected-DAG.

Quote:
In other words, main() has no idea that it is calling Inner's print method, it is just calling something's print method.
http://en.wikipedia.org/wiki/Weak_typing

I'm pretty sure this would return a compiler error in a strongly-typed language like Ada or Java.
In that sense, C++ is strongly typed. It's compiler does know that it is calling Inner:: print. For example, if I change the code to say Outer::do_stuff().Inner:: print(); I still don't get any errors.

I guess my real question is not so much why this is valid C++ in terms of "which are the relevant parts of the specification", but rather what I mean to ask is "why would anyone ever want it to be legal for a visible function to return an instance of an invisible class"?

Last edited by PatrickNew; 08-28-2009 at 12:53 AM.
 
Old 08-28-2009, 10:08 AM   #4
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,774

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by PatrickNew View Post
I mean to ask is "why would anyone ever want it to be legal for a visible function to return an instance of an invisible class"?
Instead ask "why would anyone ever want it to be illegal for a visible function to return an instance of an invisible class?" If you are looking for a programming language that tries to prevent the programmer from writing badly designed programs, C++ is most definitely not it (try Ada for that). C++ is already overcomplicated and difficult to implement without adding restrictions to prohibit all the possible useless design patterns you could write in it.
 
Old 08-28-2009, 11:29 AM   #5
PatrickNew
Senior Member
 
Registered: Jan 2006
Location: Charleston, SC, USA
Distribution: Debian, Gentoo, Ubuntu, RHEL
Posts: 1,148

Original Poster
Blog Entries: 1

Rep: Reputation: 48
Quote:
Originally Posted by ntubski View Post
Instead ask "why would anyone ever want it to be illegal for a visible function to return an instance of an invisible class?" If you are looking for a programming language that tries to prevent the programmer from writing badly designed programs, C++ is most definitely not it (try Ada for that). C++ is already overcomplicated and difficult to implement without adding restrictions to prohibit all the possible useless design patterns you could write in it.
Perhaps I should have provided the context of my question, because you make a very good point. I'm designing a language which has visibility for both classes and operations. It occurred to me one day that I was unsure how exactly this case (visible operations with invisible return types) would be handled, so I tried it in C++ to see what happens there (the object system of this language bears many similarities to the C++ object system). I figured if C++ forbid it, it was probably safe to forbid.

I just wanted to see what C++ did, and the decision surprised me. I am by no means saying that C++ should not do it that way, I'm just trying to understand what its use case is, because if some useful design requires it, then I don't want the language I'm designing to forbid useful designs.

However, if it is simply an oversight or an edge case that would be too complex to specify as invalid, then I won't worry about preserving the ability to do things like this.
 
Old 08-28-2009, 04:10 PM   #6
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,774

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
I'm designing a language which has visibility for both classes and operations. It occurred to me one day that I was unsure how exactly this case (visible operations with invisible return types) would be handled, so I tried it in C++ to see what happens there (the object system of this language bears many similarities to the C++ object system). I figured if C++ forbid it, it was probably safe to forbid.
OK, I see where your question is coming from (although I'm not sure basing language design on C++ is a good idea). I can't think of any justification for Outer promising to return a private type from a public method. It seems like a hole in the visibilty system (and the friend keyword already allows making holes wherever the programmer needs them). Maybe if you were doing something really crazy with templates...

Code:
#include <iostream>

class Outer{
  private:
    struct Inner {
      int i;
      void print() { std::cout << i << std::endl; }
    };
  public:
    static Inner do_stuff() { Inner i = { 5 }; return i; }
};

template <typename T> void func(T t)
{
    t.print();
}

int main()
{
    func(Outer::do_stuff());
    return 0;
}
Another weird thing is that Outer::do_stuff().Inner::print(); works, whereas Outer::do_stuff().Outer::Inner::print(); doesn't, but they both mean the exact same thing.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
samba question: what controls top-level share visibility? jmoody Linux - Networking 1 03-18-2009 02:49 AM
C++ Qt visibility Luis Navarro Programming 3 12-12-2008 02:02 PM
root servers and visibility jayeola Linux - Networking 3 08-21-2008 10:05 PM
People with limited visibility DC_FC79 Linux - Newbie 4 02-28-2008 02:07 PM
gcc 4.0.2 and Elf Visibility SKelem Linux - Software 3 11-07-2005 04:12 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:03 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration